This is the mail archive of the
gdb@sourceware.org
mailing list for the GDB project.
Re: GDB support for Flash memory programming
- From: Steven Johnson <sjohnson at sakuraindustries dot com>
- To: Jim Blandy <jimb at codesourcery dot com>
- Cc: gdb at sourceware dot org
- Date: Wed, 24 May 2006 12:11:46 +1100
- Subject: Re: GDB support for Flash memory programming
- References: <vt2k68c48rp.fsf@theseus.home.>
Hi,
I've been using GDB to debug programs (and load them with "load") in
flash for a long time. What I do, isn't necessarily generic, but i
thought it worth relaying given the current topic, my experience may be
useful (or not).
What I do is this:
GDB has "pre" and "post" hooks to commands. If I want to flash load,
what I do is this:
Install a "Pre" hook on load. "define hook-load" something like this:
# Set memory variables
set $FLASH_BASE=0xFFF00000
set $RAM_BASE=0x00000000
set $FLASH_SIZE=(512*1024)
define hook-load
# Initialise the target so it is downloadable.
# Macro which resets the target
TARGET_RESET
# Macro which sets the processor speed
SET_SPEED
# Macro which sets up the chip select logic
SETUP_SRAM_AND_FLASH_CS
# Macro which sets up sdram, so it can be used.
SETUP_SDRAM
# If flash contained stuff that you wanted to preserve, it could be
"copy before over-write" with another stub command like this:
# monitor memcopy $FLASH_BASE $RAM_BASE $FLASH_SIZE
# so that anything not "loaded" over would be re-written back to the
flash.
# but we don't care, so we don't do it.
# re-map memory, so a load to flash, goes to SDRAM
monitor memremap $RAM_BASE $FLASH_BASE $FLASH_SIZE
# Now any writes or reads to flash, by the remote protocol will be
re-directed from
# the flash base address to the ram base address, up to flash_size
# for example, a write to 0xFFF00300 will be remaped by the stub to be
a write to 0x00000300
# Set the size of the download packet for maximum performance.
set download-write-size 1024
end
So, before a "load" the montor (or target stub) is told to re-direct all
writes and reads to flash to an area of ram, where it is safe to do so.
The load then occurs, and the load can write to the flash area, but the
target will actually put the data loaded, in ram, at a known location.
Then I define a post-load hook, like this:
define hookpost-load
# Clear all memory remapping installed by the pre-hook.
monitor resetmemremap
# download a small flash burning stub (binary image) directly to
address 0x100000
# This works, because my monitor is in the PC, and it uses JTAG to
talk to the target
# If the monitor was resident in the target, the flash burn stub could
be part of
# the monitor and this step could be skipped
# for example, you could just call something like "monitor burn <from>
<to> <size>
# bput is a command which allows the monitor to squirt an arbitrary
binary image
# anywhere into memory, we use it to do downloads when we don't want
GDB to know
# about them
set remotetimeout 60
monitor bput utility/flashburn.bin 00100000
set remotetimeout 5
# Run the flash burn stub. By convention the first instruction of the
stub
# jumps to the stub code, and the second instruction of the stub is where
# all execution will end. It makes it easier to call stubs this way,
because
# we can easily put a breakpoint on the end of the stub execution
set $r0=$FLASH_BASE
set $r1=$RAM_BASE
set $r2=$FLASH_SIZE
break *0x100004
jump *0x100000
clear *0x100004
# After this, the flash has been programmed with the contents of
memory from address 0x00000000
# which was put there by the load.
# Macro which causes a hardware reset of the target.
TARGET_RESET
end
Then after the load has completed, the code to be loaded is in flash at
the correct place, and because the
code we are downloading here specifically is executed immediately after
a hardware reset (its the boot code)
the target is in the correct state.
As far as GDB is concerned it just "loaded" the memory, which it did,
but by these "hooks" we managed the
process of burning the load into flash (transparently).
Its a little clunky and requires some small custom commands to be added
to the monitor stub (none of which are very difficult), but it works
well is 100% reliable and is fast. Now if bput'ing and mem-remapping
(or the like) became standard commands and gdb did it, instead of the
stub, so much
better. In my opinion that's all that's really required for a GDB
generic approach, because, there are so many different targets with
different flash
programming requirements (different algorithms, 8, 16, 32 bit, etc.)
that I'm not sure a fully "generic" approach is ever going to be very
workable. At the very least, there is going to need to be different
flash programming algorithms, and then GDB is going to have to be taught
what ones are appropriate for a particular memory space on a particulat
target, and it may have multiple different ones, etc.. With the method
I describe here it doesn't matter, because the user provides a "flash
burning stub" which takes care of it for the target in question.
I have concerns about GDB "Burning" flash directly, because burning
flash directly over a JTAG interface is (in my experience) orders of
magnitude slower than burning from target ram to flash. Provided the
target has available ram to do it, i would always prefer a load to ram,
burn from there approach, because it is heaps faster, and speed matters
(especially at load). no one wants to wait 10 minutes or more, every
time they want to do a new "load" to test a bug.
Anyway, I'm not evangelising this approach, its just what I do, and it
works for me.
Steven J
Jim Blandy wrote:
>One of the problems GDB has in the embedded development world is its
>lack of support for loading programs into flash memory. After some
>conversation amongst ourselves to weed out patently stupid stuff (none
>of the text below is mine... hey), we at CodeSourcery put together the
>following proposal for general comments and criticism.
>
>We'd like to reach consensus on what the user interface should be
>before we worry about implementation details --- possible remote
>protocol changes, and so on --- so let's leave those topics aside for
>the time being.
>
>What do folks think?
>
>---
>
>Background
>
>Flash memory is a popular form of non-volatile memory. When reading,
>it is byte-addressable, like traditional RAM or ROM. An entire block
>(many kilobytes, typically) of flash can be erased with a single
>command. Individual bytes can be written only if they have been
>erased, but not subsequently written. Therefore, to write a single
>byte, without changing other bytes in the same block, one must read
>the block, erase the block, and then re-write the block using the
>previously read data, as modified by the intended write.
>
>Flash is typically used for program storage. On some systems, flash is
>in fact the only place to store programs. For example, some systems
>have have relatively large amounts of flash, but very small amounts of
>RAM.
>
>If the flash memory controller has a JTAG interface (most do) then the
>flash memory can typically be programmed using the same ICE/BDM unit
>that is used for debugging.
>
>Because GDB already communicates with these ICE units (typically via a
>GDB stub), and because GDB already supports loading programs onto
>embedded systems (via the load command), it is natural that GDB
>support loading programs into flash memory as well. This document
>proposes a GDB user interface for loading programs into flash memory.
>
>In what follows, the term "GDB" refers to the user's view of GDB,
>which includes GDB, any applicable stub, the ICE units, etc. Thus
>statements like "GDB must do X" are not meant to imply that GDB proper
>must do X, but rather that GDB must cause X to occur. Program Images
>
>If the program image loaded by the load command will result in any
>portion of the program image being placed in flash memory, then GDB is
>responsible for modifying the flash accordingly. GDB must not modify
>bytes outside of the program image itself. Therefore, if the program
>image occupies only a portion of a flash sector, GDB is responsible
>for arranging flash read/erase/write commands appropriately so as to
>avoid changing unmodified portions of the sector.
>
>If the target hardware requires any other modifications to special
>memory addresses (such as placing the initial value of the program
>counter at a specified address), then it is the responsibility of the
>programmer to ensure that the program image contains appropriate
>values at those addresses; GDB's responsibility is simply to
>accurately copy the program image to the target.
>
>The rationale for using load (rather than an alternative flash
>command) is that, on a system in which programs are located in flash,
>loading a program implies placing it in flash. Furthermore, GUIs,
>scripts, etc., that use load (or the MI equivalent thereof) will not
>require change to work with flash systems. Variables and Data
>
>By default, variables and other data located in flash may not be
>modified by the user, other than by use of the load command. For
>example, if i is located in flash, then:
>
> set var i = 10
>
>will result in an error message. (As a consequence, GDB must be able
>to determine which addresses lie in flash; otherwise, GDB, using a
>stub with a 100% transparent interface to flash, would not be able to
>issue an error.)
>
>The rationale for forbidding modification of variables is that most
>such attempted modifications probably represent user
>error. Furthermore, because setting a single variable requires erasing
>and writing an entire flash sector, there might be some noticable
>delay in implementing this request. Customization
>
>GDB will have a new write-flash variable. This variable will have
>three possible states:
>
> * on
>
> All writes to flash, including those to variables/data, are
> permitted. This mode may be used to permit explicit "poke"
> operations, like the assignment above.
>
> * load
>
> The load command may write to flash; no other commands may write
> to flash. This mode is the default.
>
> * off
>
> No commands may write to flash. This mode may be used for safety
> when debugging a production system.
>
>
>
>