JTAG & OpenOCD for LS-Pro

From NAS-Central Buffalo - The Linkstation Wiki
Jump to: navigation, search


Tampakuro/kuroguy discovered the layout of the JTAG Port on an LS Pro v1 and an early KuroPro by tracing the wiring. The account of his work and other early efforts is here : JTAG for the LS Pro and LS Live. He found that the v1 had a non-standard pinout. The v2 LS Live has a standard ARM 20 pin layout. mdfirefighter and others discovered that Dominic Rath's OpenOCD software was the key to opening the LS Pro to JTAG - this is detailed in the same thread linked to above.

At these early stages, OpenOCD did not offer any support for the Marvell 88F5182 SoC or Feroceon processor that our boxes run on, but instead we got by on limited support of a close relative, the ARM926EJS. Recent developments include some built-in support for the Feroceon in OpenOCD (revision 315 and later).

Why use JTAG?

  • JTAG provides low-level access to a flash chip. This is necessary if you need to fix a serious UBoot problem on your LinkStation, ie. you can unbrick a badly bricked LS!
  • It gives direct access to the processor (probably only useful for developers).
  • If you are developing a new bootloader, it gives you the freedom to experiment without having to worry about bricking your box.

When not to use it

JTAG access is more invasive than attaching a serial connector. It should not be your first choice if:

  • you are trying to recover from flashing a v1 UBoot to your v2 LS Pro (just use a serial connection for getting control of UBoot, and then either flash in the proper UBoot while in UBoot, or use the LS Updater while in EM)
  • you are looking for something cool to do (sane people, even developers, have been known to really break things while playing around)

Required Hardware,Software & Preparation




There is a possibility that you could brick your NAS with these instructions. Please make sure that you read the entire page carefully. WARNING: Modifying your LinkStation or Kuro can void your warranty. Incorrect flashing procedures can turn your unit into a Brick. Flashing success is not guaranteed. Do not flash your box unless your are willing to use JTAG to recover it, in the event that there is an unforeseen problem. JTAG recovery generally works well, but is not a guarantee of recovery from bricking one's box.


  • An LS Pro (or LS Live, though it hasn't been tested on the Live yet) - "...some disassembly required..."
  • JTAG headers already attached to your ARM-based LinkStation's board (see [ Add a JTAG Port] for details - you may want to consider low profile headers)
  • JTAG adapter like the Olimex ARM-USB-TINY (tested), the Amontec JTAGkey or a Wiggler (Wigglers and other paraport adapters reportedly work, but seem slower than USB)
  • an x86 desktop/laptop running Linux (tested w/ Ubuntu 7.10)

Getting, Compiling and Configuring OpenOCD

The OCD software we use is OpenOCD, created by Dominic Rath. Read through the docs there for lots of useful information. Manuals are also available in pdf form. In terms of getting OpenOCD source, you basically have two options here:

  • Build it from svn for the Feroceon support and the latest (perhaps bleeding edge) features
    • Users are encouraged to try rev 953 or later as it seems that the halt problem may be fixed in it - perhaps no patch needed
    • For svn revision 335, a patch was necessary-see Item #5 in the notes at the bottom
  • build it from our altered pre-Feroceon source, available for download from here. Note that the config file in this package, found in docs/configs/lsp_wig.cfg is already set up and tested with parallel port interfaces, like for the Wiggler.
  • Don't expect great results from the OpenOCD version that is packaged for Ubuntu or other distros, as it is somewhat dated at this point and doesn't contain the config file that members here have already set up.

  • Compiling OpenOCD - See Building OpenOCD for full details. The directions are listed below for using it with the Amontec JTAGkey and the Olimex JTAG USB TINY adapter, which are ftdi-based. Read the INSTALL file for details on building it for parallel port Wiggler devices.
    • Install libftdi (http://www.intra2net.com/opensource/ftdi/) or libftd2xx (http://www.ftdichip.com/Drivers/D2XX.htm). Most accounts seem to indicate that more users have better luck with libftdi (which is available as a package for Ubuntu, for instance.)
    • Build and install OpenOCD. Download it from the downloads on our site, or from svn at the OpenOCD site. For svn revision 335, a patch was necessary (see Item #5 in the notes at the bottom). Then bootstrap, configure, make and make install.
./configure --enable-ft2232_libftdi
make install

Also, if you are using libftdi, you may have to add the following line to your /etc/fstab:

none /proc/bus/usb usbfs defaults,devmode=0666 0 0

If you are using a parallel port Wiggler, you should read the literature and docs in the source, as they will guide you on what to do in terms of configuring before building.

  • Configuring OpenOCD - Again, see Configuring OpenOCD for details. Hints below show a config file that was used to flash a LS Pro V2 using OpenOCD svn revision 335, with an Olimex ARM-USB-TINY unit. (Note:The config file in the openocd-package in the downloads section is set up for parallel port Wiggler devices.)
# daemon config
telnet_port 4444
gdb_port 3333
daemon_startup attach

# interface
jtag_speed 0
interface ft2232
ft2232_layout "olimex-jtag"
ft2232_vid_pid 0x15ba 0x0004
# Or for the Amontec JTAGkey
#ft2232_layout "jtagkey"
#ft2232_vid_pid 0x0403 0xcff8

# use combined on interfaces or targets that can't set TRST/SRST separately
reset_config srst_only
#reset_config trst_and_srst

# jtag scan chain
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
jtag_device 4 0x1 0xf 0xe

#jtag_nsrst_delay 500
#jtag_ntrst_delay 500

# target configuration
# target <type> <endianess> <reset_mode>
# if chain_pos is not zero it seg faults
#target arm926ejs little reset_init 0
target feroceon little reset_init 0
run_and_halt_time 0 30
#working_area 0 0xc8010000 0x400 nobackup

# flash configuration
# flash bank <driver> <base> <size> <chip_width> <bus_width> [driver_options ...]
flash bank cfi 0xfffc0000 0x00040000 1 1 0 jedec_probe

Flashing U-Boot to Your LS Pro

Read through these directions completely and rehearse them for maximum success.

0. Required Software and Equipment, connected and/or ready. Attach the JTAG cable/connector to the header on your LS Pro while it is powered off. Have OpenOCD already compiled and your configuration file set up and checked.

1. Have two open windows/terminals with commands all ready to execute some commands.

  • In one terminal window, cd to the directory where your config file is located. We'll call this the OpenOCD Window from here on out. As root, type in the command
openocd  -f lsp_wig.cfg     

but do not press enter yet. The filename lsp_wig.cfg is just an example and should be changed to whatever your config file is.

  • In a second terminal window (called the Daemon Window from here on out), cd to where ever your image file for UBoot is. Then, as root, type the command
telnet localhost 4444

but do not press enter yet. Note that the Daemon Window is where all of your commands will be entered and executed through.

2. Press & hold the reset button, and press the power button on your ARM-based LinkStation. If you do this right, it will make a musical tone just a few seconds after pressing the power button.

3. Start openocd and connect to daemon by pressing enter in the OpenOCD Window, and then in the Daemon Window. You will see something like the following in those two windows, respectively:

root@bytebaker-i686:/home/davygravy/Desktop/configs# openocd  -f lsp_wig.cfg
Info:    openocd.c:86 main(): Open On-Chip Debugger (2007-04-26 16:40 CEST)
Error:   embeddedice.c:190 embeddedice_build_reg_cache(): unknown EmbeddedICE version (comms ctrl: 0x00000018)

The error seems commonplace to most of us that have used it. Until we know otherwise, most of us are assuming it is not a huge problem. OpenOCD is now running. In the Daemon Window you will see something similar to this:

root@bytebaker-i686:/usr/src# telnet localhost 4444
Connected to localhost.
Escape character is '^]'.

4. Quickly halt your processor by entering one of these commands in the Daemon Window:


You may have to go through the entire list. In any case, the processor must be halted (and maybe reset performed) in order to get flash access. You will see something like this as output in the Daemon Window:

> halt
requesting target halt...
> Target 0 halted
target halted in ARM state due to debug request, current mode: Abort
cpsr: 0x600000d7 pc: 0x00000028
MMU: disabled, D-Cache: disabled, I-Cache: enabled

or if your processor is in some state where it needs more convincing, you may see something like this:

> halt
requesting target halt...
waiting for target halted...
timed out while waiting for target halted
timed out while waiting for target halted
> reset
> soft_reset_halt
requesting target halt and executing a soft reset
value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f
in_handler reported a failed check
Target 0 halted
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
MMU: disabled, D-Cache: disabled, I-Cache: disabled

This is a stage which has proven to be unpredictably difficult. You may have to wait more than 10 seconds to get a confirmation on a halt, and you may have to repeat it. Again, no flash access is possible without a halted processor.

5. Verify and probe your flash bank by executing the following commands:

flash banks
flash probe 0

The 'flash banks' may be omitted - it is optional. The output will look similar to this:

> flash banks   
#0: cfi at 0xfffc0000, size 0x00040000, buswidth 1, chipwidth 1
> flash probe 0
flash 'cfi' found at 0xfffc0000

Once this is done, you have verified that you have proper access to the flash.

6. Erase flash bank and check erasure. Do not interrupt the process. Execute the following:

flash erase 0 0 63
flash erase_check 0

The output will look similar to this:

> flash erase 0 0 63
erased sectors 0 through 63 on flash bank 0 in 4s 484466us
> flash erase_check 0
successfully checked erase state

7. Write the UBoot image to flash. This may take anywhere from about an hour up to 5 or 6 hours. Do not interrupt the process. Execute the following:

flash write 0 lspstock052207.bin 0xfffc0000

The file to be used as an image for flash should be changed to fit your situation (the one shown is for a LS Pro V1) Note that with this command form it is expecting a full 256kb image. If you don't have a full 256kb image of the new uboot that you may have just built, you can always flash in a stock 256kb image, and then flash the new uboot from within uboot, and then dump out a 256kb image of it using mtd and dd commands.

> flash write 0 lspstock052207.bin 0xfffc0000
wrote file lspstock052207.bin to flash bank 0 at offset 0xfffc0000 in 12107s 811284us

8. To check to see if your flashing was successful (that the file you wanted to write to flash was actually written), dump it out:

dump_image currentcontents.bin 0xfffc0000 0x40000

and then in a third terminal window, compare or diff them:

diff currentcontents.bin lspstock052207.bin

The second command should return nothing if the flash contents are identical to the image file. If the contents are the same as the image file, then you have successfully flashed the ROM with that image file. If it was a valid UBoot image, then it should boot up if there is a valid OS on the hdd and the UBoot env vars are correctly set.

9. Power down and restart. This is the moment of truth. Power down the LS by either holding the power button (safest) or unplugging it. Now restart. A serial cable attachment will be your friend here as it will give an indication of success with the output of Uboot scrolling by.


Unable to halt

This seems to be the single-most frequently encountered problem for JTAG flashing of the LS Pro. Halting the processor is crucial, as there is no access to the flashbanks without it. Here are some things that one could try (at your own risk):

0. Power down the LS Pro and the JTAG adapter. This makes certain that everything is properly reinitilized on the cable and the board. On the LS Pro, this is done by just holding the power button long enough. For a USB JTAG adapter, just unplug the USB cable from the adapter. For paraport, ???.

1. Try all of these commands:


It seems that the last command, soft_reset_halt, shouldn't be helpful - at least in terms of what the documents say. But some personal experience and anecdotal evidence suggests that it is, at least in some cases.

2. Disconnect all cables and as much wiring as possible, including ethernet and the serial cable. Personal experience seems to show a difference in behavior when either of these are connected. In particular, the serial cable seems to make it very difficult to halt sometimes. This behavior has been replicated repeatedly.

3. Bridging pins. Use extreme caution and at your own risk. Any electronic device carries voltage and there is the always the risk of electrical shock. If you choose to do this, you do so at your own risk, to both yourself and your equipment. Some success has been reported with this: while executing a halt or soft_reset_halt, briefly connect the RTCK and nSRST pins. At least one user has had success by simply grounding out RTCK. Check the board for the pin names & numbers.

4. Compare to KuroPro and experiment w/ resistors. Untested and Experimental: Use extreme caution and at your own risk.. Some have suggested that the missing resistors near the JTAG header may be a piece of this puzzle. If one examines the KuroPro board and compares that to the LS Pro v2 board, it is clear that there are 4 small missing resistors on the LS Pro. As of yet, there are no reports of anyone replacing these to check for changes in function. Please let us know if you have success with this!

Need Help or Advice

If you have problems, post to the JTAG for the LSPro and LS Live thread at the forum or to the SparkFun forum for OpenOCD users. Save output from both windows, as the each offer up information that can be useful. Be as specific about your difficulties as you can be.



  1. The forum thread for this topic is JTAG for the LSPro and LS Live. Post you questions here, but search it first for solutions.
  2. For a look at development of OpenOCD see the OpenOCD Development List Archives
  3. A forum for OpenOCD users is hosted by SparkFun - great for posting problems and searching for answers.
  4. Be aware that as of svn r332, Feroceon (not a true ARM926) is still not officially supported by OpenOCD. Success is not guaranteed...at least a handful of us have flashed once or twice, and then been able to proceed with a third flash. Presumably, the processor was in a state that allowed us to do the first flash(es) but for some unknown reason comes to be in some less manageable state. The difficulty for some of us has been getting the processor halted.
  5. UPDATE: OpenOCD svn revision 335 with a small patch gave success for me, after I patched the source (acknowledgement to bbradley for the patch). In src/target/feroceon.c, find these lines:
       /* asserting DBGRQ won't win over the undef exception */
       arm7_9->use_dbgrq = 0 ;

change the 0 to 1:

       /* asserting DBGRQ won't win over the undef exception */
       arm7_9->use_dbgrq = 1 ;

and then compile normally. Note that the 'halt' command didn't work, nor did reset. The only way to get it halted was to do a soft_reset_halt and simultaneously connect pins (RTCK) and (sRST) long enough to get it to halt. (Do this at your own risk.)

root@bytebaker-i686:/home/davygravy# telnet localhost 4444
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt
requesting target halt...
waiting for target halted...
timed out while waiting for target halted
timed out while waiting for target halted
> reset
> soft_reset_halt
requesting target halt and executing a soft reset
value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f
in_handler reported a failed check


value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f
in_handler reported a failed check
Target 0 halted
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
MMU: disabled, D-Cache: disabled, I-Cache: disabled
> flash probe 0
probing failed for flash bank '#0' at 0xfffc0000
> flash probe 0
flash 'cfi' found at 0xfffc0000
> flash probe 0
flash 'cfi' found at 0xfffc0000
> flash erase 0 0 63
erased sectors 0 through 63 on flash bank 0 in 2.822007s
> flash erase_check 0
not enough working area available(requested 20, free 0)
no working area available, falling back to slow memory reads
successfully checked erase state
> flash write 0 /home/davygravy/Desktop/configs/lspro-v2flash.bin 0xfffc0000
not enough working area available(requested 96, free 0)
no working area available, can't do block memory writes
Programming at fff80000, count 00040000 bytes remaining
Programming at fff80100, count 0003ff00 bytes remaining
Programming at fff80200, count 0003fe00 bytes remaining


Programming at fffbfc00, count 00000400 bytes remaining
Programming at fffbfd00, count 00000300 bytes remaining
Programming at fffbfe00, count 00000200 bytes remaining
Programming at fffbff00, count 00000100 bytes remaining
Fixup 1 unaligned tail bytes
wrote  262144 byte from file /home/davygravy/Desktop/configs/lspro-v2flash.bin to flash bank 0 at offset 0xfffc0000 in 6522.530762s (0.039249 kb/s)
> dump_image currentcontents.bin 0xfffc0000 0x40000                         
dumped 262144 byte in 18.345442s
> exit                                                                      
Connection closed by foreign host.

Available Commands in OpenOCD svn r335

Listed for reference. While working in the telnet daemon window w/ OpenOCD, entering the command help will yield a list of available commands and summary of help. (Note: more recent versions have some changes to the names/structure of commands.)

> help
                help    display this help
               sleep    sleep for <n> milliseconds
             version    show OpenOCD version
            shutdown    shut the server down
                exit    exit telnet session
          log_output    redirect logging to <file> (default: stderr)
         debug_level    adjust debug level <0-3>
          jtag_speed    set jtag speed (if supported) <speed>
          scan_chain    print current scan chain configuration
            endstate    finish JTAG operations in <tap_state>
          jtag_reset    toggle reset lines <trst> <srst>
             runtest    move to Run-Test/Idle, and execute <num_cycles>
           statemove    move to current endstate or [tap_state]
              irscan    execute IR scan <device> <instr> [dev2] [instr2] ...
              drscan    execute DR scan  <device>  <    var  >  [dev2]  [var2] ...
    verify_ircapture    verify value captured during Capture-IR <enable|disable>
                 var    allocate, display or delete variable <name> [num_fields| del ] [size1] ...
               field    display/modify variable field < var > <field> [value|'flip']
              script    execute commands from <file>
                xsvf    run xsvf <file>
             targets    no help available
               flash    no help available
             banks -    list configured flash banks 
              info -    print info about flash bank <num>
             probe -    identify flash bank <num>
       erase_check -    check erase state of sectors in flash bank <num>
     protect_check -    check protection state of sectors in flash bank <num>
             erase -    erase sectors at <bank> <first> <last>
             write -    write binary <bank> <file> <offset>
           protect -    set protection of sectors at <bank> <first> <last> <on|off>
                nand    no help available
                 pld    programmable logic device commands
              arm7_9    arm7/9 specific commands
        write_xpsr -    write program status register <value> <not cpsr|spsr>
    write_xpsr_im8 -    write program status register <8bit immediate> <rotate> <not cpsr|spsr>
    write_core_reg -    write core register <num> <mode> <value>
          sw_bkpts -    support for software breakpoints <enable|disable>
    force_hw_bkpts -    use hardware breakpoints for all breakpoints (disables sw breakpoint support) <enable|disable>
             dbgrq -    use EmbeddedICE dbgrq instead of breakpoint for target halt requests <enable|disable>
       fast_writes -    (deprecated, see: arm7_9 fast_memory_access)
fast_memory_access -    use fast memory accesses instead of slower but potentially unsafe slow accesses <enable|disable>
     dcc_downloads -    use DCC downloads for larger memory writes <enable|disable>
          etb_dump -    dump current ETB content
             armv4_5    armv4/5 specific commands
               reg -    display ARM core registers
        core_state -    display/change ARM core state <arm|thumb>
       disassemble -    disassemble instructions <address> <count> ['thumb']
            arm9tdmi    arm9tdmi specific commands
      vector_catch -    catch arm920t vectors ['all'|'none'|'<vec1 vec2 ...>']
           arm926ejs    arm926ejs specific commands
              cp15 -    display/modify cp15 register <opcode_1> <opcode_2> <CRn> <CRm> [value]
        cache_info -    display information about target caches
         virt2phys -    translate va to pa <va>
          mdw_phys -    display memory words <physical addr> [count]
          mdh_phys -    display memory half-words <physical addr> [count]
          mdb_phys -    display memory bytes <physical addr> [count]
          mww_phys -    write memory word <physical addr> <value>
          mwh_phys -    write memory half-word <physical addr> <value>
          mwb_phys -    write memory byte <physical addr> <value>
                 cfi    no help available
                 reg    no help available
                poll    poll target state
           wait_halt    wait for target halt [time (s)]
                halt    halt target
              resume    resume target [addr]
                step    step one instruction
               reset    reset target [run|halt|init|run_and_halt|run_and_init]
     soft_reset_halt    halt the target and do a soft reset
                 mdw    display memory words <addr> [count]
                 mdh    display memory half-words <addr> [count]
                 mdb    display memory bytes <addr> [count]
                 mww    write memory word <addr> <value>
                 mwh    write memory half-word <addr> <value>
                 mwb    write memory byte <addr> <value>
                  bp    set breakpoint <address> <length> [hw]
                 rbp    remove breakpoint <adress>
                  wp    set watchpoint <address> <length> <r/w/a> [value] [mask]
                 rwp    remove watchpoint <adress>
          load_image    load_image <file> <address> ['bin'|'ihex']
          dump_image    dump_image <file> <address> <size>
         load_binary    [DEPRECATED] load_binary <file> <address>
         dump_binary    [DEPRECATED] dump_binary <file> <address> <size>  

Manuals for OpenOCD

Manuals for the latest versions can be made by cd-ing to the source and doing "make pdf". Ready-made manuals are provided here for your convenience.

for OpenOCD svn r335

Manual availabe in pdf format : OpenOCD Manual for svn r335

for OpenOCD svn r479 - with newer commands

Manual available in pdf format : OpenOCD Manual for svn r479