Skip to content

Commit

Permalink
coldboot/doc: document bootstrapping sequence
Browse files Browse the repository at this point in the history
  • Loading branch information
tomlogic committed Sep 13, 2020
1 parent 21e4e3a commit 4e527a9
Showing 1 changed file with 157 additions and 0 deletions.
157 changes: 157 additions & 0 deletions ColdBoot/README-bootstrapping.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
Bootstrapping Rabbit 2000/3000 hardware, as implemented by the Rabbit Field
Utility (RFU). This is just a rough description of the process based on
serial capture and review of coldload, pilot and RFU source code.

This process loads Bios/Coldload.bin at 2400bps via triplets, then jumps to
57600 to load Bios/Pilot.bin. It then communicates with the Pilot BIOS to
write firmware to the board's flash memory.

First, use triplets at 2400bps to load COLDLOAD.BIN:

* Open serial port at 2400bps, no parity, 8 data bits, 1 stop bit.
* Clear RTS (loopback to CTS) and DTR (wired to /RESET).
* Set RTS and DTR (asserting DTR holds processor in reset).
* Clear DTR (bring processor out of reset).
* Send optional "Processor Verification" triplets before the cold loader.
Disables the watchdog timer, and then sets GOCR to toggle the STATUS pin
which we can read via DSR.
* 80 09 51 ; write 0x51 to WDTTR
* 80 09 54 ; write 0x54 to WDTTR
* 80 0e 30 ; write 0x30 to GOCR, wait 100ms and check for DSR high
* 80 0e 20 ; write 0x20 to GOCR, wait 100ms and check for DSR low
* Send 80 0e 20 to write 0x20 to GOCR, bringing STATUS (DSR) low.
* Send tripletted cold loader, inserting 80 0e 30 (write 0x30 to GOCR to
bring DSR high) before the cold loader's 80 24 80 (write 0x80 to SPCR)
which starts the program.

Now that the cold loader is running, use it to upload PILOT.BIN:

* Switch to 57600bps.
* Set RTS, clear DTR (already cleared previously).
* Write 00 40 00 00 8d 15 e2
* Pilot BIOS physical address 0x00004000, 0x158D bytes, 0xE2 checksum of
command.
* Read back e2 (cold loader's calculated checksum)
* Send complete Pilot BIOS (cold loader waiting for starting byte of 0xCC)
* Cold Loader will replace 0xCC with 0x00 (NOP) in RAM, but uses 0xCC in
the 8-bit Fletcher checksum.
* See premain/main of PILOT.C for `db 0CCh` marker byte.
* Read back 69 d4 (8-bit Fletcher checksum of PILOT.BIN = 0xD469; see
coldload.c for algorithm).

Now we're running the Pilot BIOS. Use it to upload a firmware image to flash:

* Clear RTS and DTR.
* Increase baud rate to 460800. RTS and DTR still cleared.
* This is likely the RFU identifying the top speed it can use to upload
the firmware image. If switching to 460800 failed for some reason,
it would probably check 230400.
* Decrease baud rate to 57600. RTS and DTR still cleared.

We are now communicating with the Pilot BIOS. It sends frames starting
with 7e 02 00 00 and then a "subtype" byte. Responses start the
same way, ORing subtype with 0x80 for ACK and 0x40 for NAK . If 7d or 7e
appear anywhere in the frame other than the 0x7E start of frame, they are
replaced by 7d 5d or 7d 5e respectively.

* Write "Set Baud Rate" command to increase baud rate to maximum
(460800 = 0x00070800): 7e 02 00 00 06 04 00 26 0c 00 08 07 00 b5 4d
* Read the ACK: 7e 02 00 00 86 00 00 9f 88 78 b0
* Change baud rate to 460800, RTS and DTR still cleared.

* Write "Info Probe" command: 7e 02 00 00 04 00 00 18 06 5a 24
* Read the ACK header: 7e 02 00 00 84 af 00 f8 36
* Start of response 7c ff 0f 00 d7 bf 08 24 01 01 00 00
* uint32_t location (0x000FFF7C)
* uint16_t flash_id (0xBFD7)
* uint8_t ramsize (0x08)
* uint8_t divisor_19200 (0x24, frequency divider for 19200bps)
* uint32_t cpu_id (0x00000101, Rabbit 3000r1; see TCData.ini)
* Followed by System ID Block ending in 55 aa 55 aa 55 aa
* Finally a 2-byte checksum of the frame.
* Reference Dynamic C libraries for format of System ID Block.

* Look up the flash ID in Dynamic C 9's FLASH.INI file to get sector size,
number of sectors, flash size and write mode.
* Write "Flash Parameters" command with 16-bit sector size, number of sectors,
flash size (shifted right 12 bits; a multiple of 4KB) and write mode:
7e 02 00 00 0a 08 00 3a 14 00 10 80 00 80 00 01 00 75 74
In this example, an RCM3209:
* 0x1000: 4KB,
* 0x0080: 128 sectors,
* 0x0080: 512KB
* 0x0001:
* Read the ACK: 7e 02 00 00 8a 00 00 ab 8c a8 c4

* Write "Erase Flash" command with max address of 0x0008cf50. In this case,
firmware image is 0xCF50 bytes. Flash mapped to base of 0x80000, hence the
max address of 0x0008XXXX: 7e 02 00 00 09 04 00 2f 0f 50 cf 08 00 b0 75
* Read the ACK: 7e 02 00 00 89 00 00 a8 8b 9c bf

* Send 128-byte chunks of firmware image, wrapped in consistent header
(7e 02 00 00 03 87 00 24 8c CC BB AA ZZ YY XX WW) with 2-byte footer.
CC is the address type field:
* 0x00 Physical (0xWWXXYYZZ is physical address)
* 0x01 Logical (0xWWXX is XPC, 0xYYZZ is offset)
* 0x03 No XPC (??)
Pilot writes block of 0xAABB bytes to address 0xWWXXYYZZ.
* Read the ACK (always this sequence): 7e 02 00 00 83 00 00 96 85 54 a1

* A smaller chunk at the end of the file (0x0050 bytes at offset 0x0008CF00)
had this header: 7e 02 00 00 03 57 00 c3 5c 00 50 00 00 cf 08 00

* When upload complete, send "Start" command:
7e 02 00 00 05 01 00 1d 08 02 9e 2f.
Length is always 0x0001. Data byte values:
* 0x01 RAM Program, just jump to 0x0000
* 0x02 Flash program, remap quadrant 0 to flash and jump to 0x0000

* Then set baud rate to 115200 (likely unnecessary), clear RTS and DTR
(should already be cleared), and close the serial port.


Packet Header:
uint8_t start_byte; // 0x7e
uint8_t protocol_version; // 0x02
uint8_t flags; // 0x00 (unused)
uint8_t type; // 0x00
uint8_t subtype; // See list of subtypes below
uint16_t data_length; // Length of data
uint16_t header_checksum; // Standard Internet checksum of header bytes

/* Variable Length Data */

Packet Footer:
uint16_t checksum; // Standard Internet checksum of header and data

Subtype:
0x06: Set Baud Rate
0x04: Info Probe
0x0a: Send Flash Parameters to Pilot based on Flash ID from Info Probe
0x09: Erase Program Flash
0x03: Write
0x05: Start BIOS

Checksums calculated as:
void TConnection::DoChecksum(uint8* data, int length, unsigned short& checksum)
{
unsigned short c0, c1;
c0 = checksum >> 8;
c1 = checksum & 0x00ff;
for(int i = 0; i < length; i++)
{
c0 = c0 + data[i];
if(c0 & 0x100)
{
c0++;
c0 &= 0x00ff;
}
c1 = c0 + c1;
if(c1 & 0x100)
{
c1++;
c1 &= 0x00ff;
}
}
checksum = (c0 << 8) | c1;
}

0 comments on commit 4e527a9

Please sign in to comment.