This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GDB support for flash: implementation


Thanks very much to the folks who contributed to the thread the other
week about GDB's flash programming support!  Based on the feedback,
I've made the following adjustments to our user interface sketch/spec:

* Drop the requirement that 'load' preserve the contents of those
  portions of the flash that the binary being loaded doesn't touch.
  Since erase operations affect entire sectors, these semantics would
  require a read-erase-write cycle covering, in the worst case, a
  complete flash sector.  When programming flash directly over a JTAG
  interface, it's not unusual for it to take tens of seconds to write
  a sector; this is an unacceptable cost when the user knows the old
  contents aren't worth preserving.

* Note that we could extend GDB's memory region facilities to
  establish different settings for different regions of flash, or for
  different flash devices.  However, we'll leave developing this idea
  for later.

But with those changes, people seemed to feel that the facilities
proposed would cover their daily use cases.

So I think now we can start talking about the implementation.  Here's
an edit of the original document that goes further and describes an
implementation that seemed reasonable to us; search down for
"Implementation".

So, what do people think?  Would this proposal work for you?

----

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.

Rationale paragraphs appear in (parenthesis).


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 programming those portions of the flash
accordingly. GDB may also arbitrarily modify bytes in flash that fall
outside of the program image.

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.)

(The proposal originally required the load command to leave portions
of flash that fell outside the program image unchanged. While this
rule would minimize side effects, it may be impractical to follow on
some devices. Since erase operations affect entire sectors, preserving
bytes outside the image would require a read-erase-write cycle
covering, in the worst case, a complete flash sector. When programming
flash directly over a JTAG interface, it's not unusual for it to take
tens of seconds to write a sector; this is an unacceptable cost when
the user knows the old contents aren't worth preserving. However, it
might be valuable to provide the original behavior as an option.)


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.

    * 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.

(In the future, we may want to adapt GDB's memory regions to allow
different parts of the address space to carry different settings.)


Implementation

There are many different flash devices in general use, from many
different manufacturers. The algorithms required to load new data into
flash vary from one chip to the next. Some devices support more than
one programming method; the best choice may depend on what resources
are available elsewhere in the system (RAM for buffering, and so on).

To contain this complexity, code specific to particular flash devices
is placed in the GDB stub, and GDB itself uses flash-specific but
device-independent remote protocol requests and replies to program the
flash.

The GDB load command initially tries to place the program image in
memory using ordinary memory write requests --- remote protocol M or X
requests. However, when the stub detects that GDB has attempted to
write to flash memory, it returns an error code of the form:

        Eflash:addr;length

In this reply, addr and length are the start address and length of the
block of flash memory the write request attempted to modify. That is,
a write that overlaps any portion of a region of flash memory elicits
an Eflash response giving the location and size of the entire flash
memory. If the write request overlaps two areas of flash, the Eflash
request reports the lowest-addressed area. When the stub returns an
Eflash result, it should discard the entire write request; if portions
of the request cover non-flash memory, the contents of that memory
should be unchanged.

GDB's reaction to an Eflash response depends on the current
write-flash setting. If write-flash is off, or if it is load and the
write was not part of an image load, GDB displays an error message to
the user, and gives up on the command. Otherwise, GDB follows this
procedure::

    * First, it sends zero or more packets of the following form to
      the stub:

        vFlashErase:addr;length

      This directs the stub to erase all flash sectors that overlap
      with the region from addr to length. The region need not be
      aligned on flash sector boundaries, and may cover any number of
      sectors; it is the stub's responsibility to expand the region to
      the smallest set of sectors that completely contains the given
      region.

    * Then, it sends the data to be loaded into flash using packets of
      the following form:

        vFlashWrite:addr,length:data

      where addr, length, and data all have the same form as they do
      in the X binary download packet. The set of vFlashWrite packets
      preceding a vFlashDone packet (see below) must not overlap, and
      must appear in order of increasing address.

      Writes may fall outside the regions given by the previously
      transmitted vFlashErase packets, but the results are
      unpredictable if a given area of flash is rewritten without
      being erased.

    * Finally, it indicates that all the data to be programmed has
      been sent, with a packet of the form:

        vFlashDone

      Until the vFlashDone packet is received, the effects of prior
      vFlashErase and vFlashWrite packets may be unpredictable.

Receipt of an Eflash response to a memory write indicates that the
stub supports the vFlashErase, vFlashWrite, and vFlashDone requests.

(Rationale:

    * The Eflash response allows the stub to screen writes to
      flash. It would certainly be possible for GDB itself to screen
      writes by address, and it could be useful for GDB to have
      detailed knowledge of the target's address space for other
      reasons as well. However, stub-based screening is also an
      important case to support, because it allows detailed knowledge
      of the device to be held in software more tightly coupled to the
      device than GDB is. And it's simple: on targets with a single
      flash device, the stub need only make a simple address overlap
      comparison and return a fixed-string Eflash response.

    * By itself, the existing X packet is not suitable for flash
      programming. To allow multiple X packets to load data into the
      same flash sector, X would have to follow a save-erase-combine
      procedure, which can be extremely slow on some devices. So a
      separate erasure packet, at least, is necessary.

    * It is possible to use the X packet for both flash programming
      and ordinary memory writes, instead of introducing a new
      vFlashWrite packet. However, the procedure for programming flash
      can be very different from the procedure for writing ordinary
      memory --- for example, many devices require some handshaking to
      allow them time to complete the write --- so the code handling
      the X packet would need to dispatch to different routines
      depending on the address anyway. It seems simpler to restrict X
      to writing ordinary memory, and introduce a new packet for flash
      programming.

      Also, using separate packets for memory writes (X, M) and flash
      writes (vFlashWrite) makes it easy for the stub to tell whether
      to respond to a write request with an Eflash result, or whether
      to call the flash-programming code. Certainly, the stub could
      keep track of whether the write occurs between a vFlashErase and
      a vFlashDone, but that would make the protocol stateful, and
      thus a bit more fragile.

      Finally, using separate packets makes it unnecessary for the
      stub to handle writes overlapping different kinds of memory,
      removing some complexity.

    * We allow writes without preceding erases in order to support
      cases where the user understands the mechanics of their flash
      device, and knows that a given combination of writes will work
      as intended. For example, a flash-without-erase command could
      allow a careful user to combine several program images on a
      single flash sector.

    * Some devices allow faster programming in blocks. Requiring
      vFlashWrite packets to appear in order of increasing address and
      requiring GDB to send a vFlashDone packet when all the data has
      been transmitted allow the stub to buffer data into blocks, and
      then write them when the buffer is full, or when all data has
      been transmitted.)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]