view bootrom.notes @ 405:f7df0f4d7d4f

tfo/find-is-hdr.c: print found offset in hex
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 18 Mar 2023 05:57:23 +0000
parents cf3b4cb3d212
children
line wrap: on
line source

Application images in flash:

In order for the nCS0 flash content to be considered a valid bootable image
(i.e., for the boot ROM to transfer control to it, rather than wait forever
for a UART download), the 32-bit word at address 0x2000 (the first word
after the ROM-overlaid portion) must contain either 0 or 1, corresponding
to two supported environment options:

* If the word at 0x2000 equals 0, it signifies an application image that is
  designed to run with the boot ROM still mapped at 0, with ARM exceptions
  vectoring through the 7 magic RAM locations at 0x80001C, and possibly
  through the 2nd level ("user-friendly") vector table at 0x800000 as well.

  If the word at 0x2000 equals 0, the following word at 0x2004 must contain
  the absolute address of the boot entry point; the boot ROM will transfer
  control to that address with the FFFF:FB10 register set to explicitly map
  the internal boot ROM at 0.  It is a BX-style address: setting the least
  significant bit will result in control being transferred in the Thumb state.

* If the word at 0x2000 equals 1, it signifies an application image that is
  at least conceptually independent of the Calypso boot ROM - one that would,
  at least in theory, function correctly with nIBOOT tied/pulled/driven HIGH,
  or even on an older DBB chip with no internal boot ROM.

  When the boot ROM code sees a 1 in the 0x2000 word, it copies a little piece
  of code into the internal RAM and runs it there; this code sets the FFFF:FB10
  register to disable the internal boot ROM (map the external nCS0 memory at 0,
  as if nIBOOT were high) and causes the watchdog timer to go off, resetting
  the ARM core and causing it to execute the external nCS0 reset vector.

UART protocol

The external host initiates every operation by sending a command to the
Calypso target running the boot ROM code.  Every command begins with '<' and
a lowercase ASCII letter; just the initial '<' is sufficient to interrupt
the flash image autoboot.  The external host shound send these commands at
19200 baud, 8N1, and the boot ROM will intuit whether the Calypso is being
clocked with 13 or 26 MHz by trying the two possible clocking setups
alternately, with the UART baud rate registers set to /42 in both cases,
until a clean '<' is received.

Once the initial '<' has been received on either UART, the boot ROM only
listens on that port from there onward.  There is a timeout between the
successive bytes of a single command, but the ROM will wait forever
for another '<'.

Commands:

<a

Seems to be a reset command that throws everything back to the initial state.
Does not seem to produce a response.

<b

Branch command.

Followed by 4 bytes, giving the 32-bit branch address in MSB-first order.
It is a BX-style address, i.e., setting the least significant bit will
cause the code to be jumped to in the Thumb state.

The address is written to 80052C, and the 0x2c8 function returns code 6.

If the command is accepted, a '>b' response is sent back before the
jump is performed.  If the command is rejected because the downloader
is in the wrong state (see below), a '>B' response is sent back, and
the downloader is reset to its initial state, waiting for commands at
19200 baud.

<c

Checksum verification command.  The <c characters need to be followed by a
single binary byte, which need to equal the one's complement of the low byte
of the 800528 accumulator.

Response: >c if good, >C if bad.  Both are followed by the low byte of 800528.

<i

Calls the 0x11c routine, then responds with '>i'.

<p

Set parameters

Followed by 9 bytes:
	1 byte: goes into var at 800518, selects the baud rate:
		0: 115200
		1:  57600
		2:  38400
		3:  28800
		4:  19200
	1 byte: goes into var at 800521, controls the 0xef4 routine:
		bits <6:2>: R2 arg (PLL_MULT field)
		bits <1:0>: R1 arg (PLL_DIV field)
	2 bytes: 16-bit MSB-first value goes into var at 800522
		word gives arguments to 0xe2c routine, breaks down as follows:
			bit 15: unused
			<14:10> arg3
			<9:5>	arg2
			<4:0>	arg1
	1 byte: goes into var at 800525
		remaining arguments to 0xe2c:
			<7:4>	arg5
			<3:0>	arg4
	4 bytes: 32-bit MSG-first value goes into var at 80051C
		reloads the UART timeout variable 800104

Good response: >p 00 04 (4 bytes total)
The baud rate is switched after the above response is sent.

Error response: >P

<w

Write data to RAM

Followed by:
	1 byte: block number (of this block)
	1 byte: total # of blocks
	2 bytes: # of payload bytes in this block (MSB first)
	4 bytes: load address for this block (MSB first)
	data

For a single block (both bytes after <w set to 01), the maximum allowed
payload length is 1015 (0x3F7) bytes.

No alignment required on the address or length - the copying from the
intermediate buffer at 80010C to the specified load address is done
with a loop that does one byte at a time with ldrb and strb instructions.

The checksum of each block is computed as a simple ripple-carry sum
(in a 32-bit ARM register) of:
	+ the word-sized payload byte count from the command
	+ each of the 4 bytes of the load address
	+ constant 5
	+ each byte of the payload data

The code then takes a one's complement of the least significant byte
of the above sum, and adds that (plain ripple-carry addition)
to the accum in 800528 (a 16-bit variable).

Good response: >w
Error response: >W <err code byte from 800531>

UART download procedure

Step 1: the external host sends a continuous stream of '<i' beacons at 19200
baud, waiting for a '>i' response at the same baud rate.  These beacons need
to be pouring down the wire into the Calypso UART while waiting for the user
to induce the Calypso target into executing the boot ROM (via battery
manipulations or other target-specific tricks).

Step 2: when a '>i' response has been received, send a '<p' command with the
desired parameters.  Expect a '>p' 00 04 response, still at the original
baud rate of 19200; if this response isn't received, it's an error.

Step 2a: if the '<p' command specified a switch to a higher baud rate (up to
115200), have the external host switch its serial port configuration at this
point, after getting the >p response but before sending the next command.

Step 3: send a series of '<w' commands, loading code into IRAM.  (Only the
internal Calypso RAM may be loaded, not board level RAM.)  Maintain a
running checksum like the boot ROM does.

Step 4: send a '<c' command with the proper checksum value.  A positive
response must be received before one can proceed to the branch.

Step 5: send a '<b' command to transfer control to the just-loaded code.

The implementation of this protocol on the boot ROM side contains a state
machine which enforces the above order:

* a '<p' command is required before '<w' will be accepted
* after that '<p', one or more '<w's and a '<c' with the correct checksum
  value must be received in order to enable the '<b' command.

Errors result in the state machine being reset to the initial state;
the baud rate at which the boot ROM expects to receive commands reverts
to the initial 19200.

RAM layout:

800000 7 words:
	soft-vector pointers: by default the following 7 words at
	80001C are filled with ldr-jump instructions, which read
	from these 7 words and load them into PC
80001C 7 words:
	hard vectors: the physical vector locations in the ROM
	contain branch instructions to these 7 RAM addresses
800038:	The helper routine for transferring control to type 1 flash images
	is copied to and run here.
800100:	the last word of the above routine
800104: word initialized to 0x0001D4C0 - tells the 0x2c8 routine
	how long to wait for a character
800108: byte initialized to 0x01
	state variable for the serial command interface
	in the initial state of 01, only <i and <p are accepted
	state 02: after successful <p, <w is allowed
	state 03: after first successful <w, and subsequent successful <w's
	state 04: after <c with matching checksum
80010C: all bytes of a '<w' command after these two command chars
	are stored starting here
	this buffer is also used for other scratchpad functions: <p
	command bytes, all response messages
80050B: the above buffer ends here

The group of vars starting at 800518 may have been envisioned
as a struct - see the routine at 0x11c:

800518:	byte variable receives the first parameter byte after '<p'
	baud rate code ([0,4] range)
	init to 04 by '<i'
80051C: 32-bit var set by the '<p' command
	reloads the UART timeout variable 800104
800520: byte variable filled every time the 0xfb4 routine is called
	holds the ID of the UART on which '<' came in, or FF if none
800521:	byte variable receives the 2nd parameter byte after '<p'
	PLL config
800522:	16-bit var set by the '<p' command
	chip select wait state config
800524: byte variable filled every time the 0xfb4 routine is called
	filled with a copy of 800534
800525:	byte var set by the '<p' command
	config for the FFFF:F900 register (0xe2c routine)
800526: 16-bit var init to 0 by 0x11c ('<i' handler)
	byte following the '<c' command is extended to a half-word and
	written here
800528: 16-bit var init to 0 by 0x11c ('<i' handler)
	checksum accum?

80052C:	32-bit var init to 0 by 0x11c ('<i' handler)
	word holds the argument of the '<b' command, i.e., the branch address
800530: byte indicates validity of the received '<w' command:
	0 means valid, 1 means something bad
	init to 0 by 0x11c
800531: byte error code to return to host as the 3rd (and last) byte
	of the >W message
	set to 02 if the 800530 flag was set
	set to 01 if the 0x730 routine detects bad address

800534: byte initialized to 0x00, then may be set to 1 by the 0xfb4
	routine if it selects /1 clock mode.

8005C0: appears to be the intended low address (bottom) of the stack
80074C: top of the stack (initial value loaded into SP)
800750: lowest address at which user code may be loaded