# HG changeset patch # User Mychaela Falconia # Date 1537571312 0 # Node ID 85c65bc1d03325a8c442619c41a2a55582f7465b # Parent cbd944ebeff0164468ebeeff47990c7935ee2331 leo-obj/bootloader/Notes: bootloader blob reverse-engineered diff -r cbd944ebeff0 -r 85c65bc1d033 leo-obj/bootloader/Notes --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/leo-obj/bootloader/Notes Fri Sep 21 23:08:32 2018 +0000 @@ -0,0 +1,105 @@ +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()