view leo-obj/bootloader/Notes @ 276:85c65bc1d033

leo-obj/bootloader/Notes: bootloader blob reverse-engineered
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 21 Sep 2018 23:08:32 +0000
parents
children
line wrap: on
line source

The present bootloader.lib blob contains not one but two bootloaders inside,
speaking different protocols.  There is the original TI GSM bootloader, and
then there is the so-called FLUID bootloader.  The original TI GSM bootloader
initializes both UARTs at what was intended to be 115200 baud, but will actually
result in 230400 baud on 26 MHz hardware, as there is no VCLKOUT_DIV2 or
VTCXO_DIV2 setting done anywhere.  Then it provides a certain time window
during which it listens on both UARTs for a bootloader command packet, and if
it gets a COM_GET_MONITOR_ID command, it will respond to it and stop the normal
flash boot process.  It will then listen for further command packets without a
timeout.  It appears that this bootloader was originally designed with commands
that write directly to flash, but the present version no longer has any of those
commands, and instead it has commands to load a code image into RAM and to jump
to it.

The so-called FLUID bootloader is a separate beast with its own self-contained
code and its own serial protocol.  There is one special command packet that can
be sent to the first bootloader that will cause it to call fluid_bootloader(),
and the latter function never returns.  The FLUID bootloader reinitializes both
UARTs again (same baud rate, and same bogosity on 26 MHz platforms), and then
it sends out a continuous stream of 'H' (hello) characters on both UARTs until
it hears a response, telling it which UART it should use for further
communication.

Commands for the original (pre-FLUID) bootloader are binary strings or packets
of the following format:

* begin with 0xAA byte
* the byte after the initial 0xAA is the number of bytes to follow,
  including stuffing bytes
* the payload bytes follow, if there is 0xAA in the payload, it is duplicated

The command to enter the FLUID bootloader is just 0xDD (one byte) before
string encoding, or 0xAA 0x01 0xDD in the full packet form which the host
needs to send.  The native commands for the first bootloader are:

0x00 = COM_GET_MONITOR_ID
0x09 = COM_LOAD_APPLICATION
0x0A = COM_SEND_RUN_ADDRESS

COM_GET_MONITOR_ID and COM_LOAD_APPLICATION take no arguments, i.e., just
0xAA 0x01 and the opcode.  After receiving COM_LOAD_APPLICATION, the bootloader
will switch to expecting S-records: you need to send it a complete S-record
image consisting of an S0 header record, one or more S3 payload records and a
terminating S7 record.  Each S-record is sent as follows: the 'S' character and
the record type digit are sent literally in ASCII, then the rest of the record
(starting with the length byte and ending with the checksum) is sent as binary
bytes.  No CR or LF characters are sent over the wire.  The code is designed to
take *.m0 S-record images produced by TI's hex470: the S0 and S7 records must
be exactly as produced by that tool, no variations allowed, and the data format
is 16-bit word-oriented with the upper byte first, i.e., byte-reversed relative
to the natural ARM little-endian byte order.

COM_SEND_RUN_ADDRESS opcode is followed by 4 bytes of address in MSB-first byte
order, for a total pre-stuffing command packet length of 5 bytes.  This command
packet is the only one in the present version for which 0xAA escaping may be
needed.  The transfer of control is done with BX.

cmdboot.obj:

cmd_check_application_in_flash(): checks the 32-bit word in flash where the
IRQ vector branch points, returns 1 if the word is not all-1s (good image)
or 0 otherwise (bad image).

convert.obj:

This module has 0x10 bytes of purely local (static) bss.

con_initialize_conversion(): sets 32-bit words at .bss+4 and .bss+0xC to 0.

serial.obj:

.bss+4: byte var initialized to 0 in ser_initialize_flash_data_detection()
appears to be a boolean flag indicating if the S0 header record
has already been received or not

.bss+5: S-record checksum accumulator

.bss+7: byte var initialized to 0 in ser_initialize_flash_data_detection()
used to decide if we are looking for the 'S' character or for the digit
immediately after the 'S'

.bss+0xC: 32-bit var initialized to 1 in ser_initialize_flash_data_detection()
0 = receiving payload data bytes
1 = expect beginning of S-record
2 = expect the bytes after S0
3 = expect the bytes after S7
4 = expect the bytes after S3
5 = state after the S3 record length byte (receiving address bytes)
6 = expect S3 record checksum byte

ser_initialize_serial_link(): both UARTs are initialized sensibly, the baud
rate divisor is set to 7.

start.obj:

static function at 0x0: an init function called immediately at the beginning
by sta_select_application().  This function disables all interrupts, stops the
watchdog timer, and puts the DPLL into bypass mode with the external clock
pass-thru, removing the division by 2 set by the bogus code in bootloader.s.

sta_select_application():
calls the static function at 0x0
calls ser_initialize_serial_link()
calls con_initialize_conversion()
calls cmd_check_application_in_flash()