📄 dloadarm.c
字号:
===========================================================================*/
static void transmit_response
(
response_code_type rsp
/* Type of response to transmit */
)
{
const byte *pkt;
/* Pointer into the packet being transmitted */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
pkt = response_table[rsp]; /* Find the packet to transmit */
uart_transmit_byte(ASYNC_HDLC_FLAG); /* Supply the leading flag */
do
{
uart_transmit_byte(*pkt); /* Transmit bytes from the buffer */
}
while (*pkt++ != ASYNC_HDLC_FLAG); /* Until we've transmitted a flag */
} /* transmit_response() */
/*===========================================================================
FUNCTION rcv_packet
DESCRIPTION
This function receives a complete packet using the generic UART
service uart_receive_byte. It takes care of the async-HDLC state
machine, enforces a minimum packet length of 1 byte plus CRC, and
checks the CRC on the fly.
DEPENDENCIES
Uses the crc table.
RETURN VALUE
Once a good packet is received, returns its length including
but not including flags or byte stuffing escapes.
SIDE EFFECTS
If a NAK-able packet error is detected, this function generates a
suitable NAK response and does not return until a good packet is
received.
The watchdog is reset.
===========================================================================*/
static word rcv_packet
(
byte *buf
/* Pointer to the packet buffer for receiving the packet */
)
{
enum
{
HDLC_HUNT_FOR_FLAG, /* Waiting for a flag to start a packet */
HDLC_GOT_FLAG, /* Have a flag, expecting the packet to start */
HDLC_GATHER, /* In the middle of a packet */
HDLC_PACKET_RCVD /* Now have received a complete packet */
} state;
/* State variable for decoding async HDLC */
int chr;
/* Current character being received */
word len;
/* Length of packet collected so far */
word crc=0;
/* Cyclic Redundancy Check, computed as we go. */
/*lint -esym(644,len,crc) */
/* Lint can't tell that the state machine guarantees that
we initialize len and crc before use */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Look at characters and try to find a valid async-HDLC packet of
length at least MIN_PACKET_LEN with a valid CRC.
Keep looking until we find one. */
len=0;
for (state = HDLC_HUNT_FOR_FLAG; state != HDLC_PACKET_RCVD; /* nil */)
{
BOOTHW_KICK_WATCHDOG(); /* Don't let the watchdog expire */
chr = uart_receive_byte(); /* Get next character (wait for it) */
if (chr == UART_RX_ERR) /* If it's an error ... */
{
state = HDLC_HUNT_FOR_FLAG; /* Start over. */
continue;
}
/* initial communication timed out */
if (chr == UART_TIMEOUT)
{
boot_powerdown_entry();
}
switch(state) /* Process according to which state */
{
/*lint -esym(788,HDLC_PACKET_RCVD) No need to deal with HDLC_PACKET_RCVD
since we're in a loop that guarantees we're not in that state. */
case HDLC_HUNT_FOR_FLAG: /* We're looking for a flag ... */
if (chr == ASYNC_HDLC_FLAG) /* and we got one ... */
{
state = HDLC_GOT_FLAG; /* so go on to the next step. */
}
break;
/*- - - - - - - - - - - - - - - - - - -*/
case HDLC_GOT_FLAG: /* Had a flag, now expect a packet */
if (chr == ASYNC_HDLC_FLAG) /* Oops, another flag. No change. */
{
break;
}
else
{ /* Ah, we can really begin a packet */
len = 0; /* The packet starts out empty */
crc = CRC_16_L_SEED; /* and the CRC in its initial state */
state = HDLC_GATHER; /* and we begin to gather a packet */
/* Fall through */ /* (starting with this byte) */
}
/*- - - - - - - - - - - - - - - - - - -*/
case HDLC_GATHER: /* We're gathering a packet */
if (chr == ASYNC_HDLC_FLAG) /* We've reached the end */
{
if (len < MIN_PACKET_LEN) /* Reject any too-short packets */
{
transmit_response(NAK_EARLY_END); /* Send NAK */
state = HDLC_HUNT_FOR_FLAG; /* Start over */
}
else if (crc != CRC_16_L_OK_NEG) /* Reject any with bad CRC */
{
transmit_response(NAK_INVALID_FCS); /* Send NAK */
state = HDLC_HUNT_FOR_FLAG; /* Start over */
}
else /* Yay, it's a good packet! */
{
state = HDLC_PACKET_RCVD; /* Done for now */
}
break; /* However it turned out, this packet is over. */
}
/* It wasn't a flag, so we're still inside the packet. */
if (chr == ASYNC_HDLC_ESC) /* If it was an ESC */
{
chr = uart_receive_byte(); /* Get the escaped byte */
if (chr == UART_RX_ERR) /* If there was an error, */
{
state = HDLC_HUNT_FOR_FLAG; /* Start over */
break;
}
chr ^= ASYNC_HDLC_ESC_MASK; /* Otherwise, de-mask it */
/* No break; process the de-masked byte normally */
}
if (len >= MAX_PACKET_LEN) /* Make sure there's room */
{
transmit_response(NAK_TOO_LARGE); /* Oops, buffer too full */
state = HDLC_HUNT_FOR_FLAG; /* Start over */
}
else
{
buf[len++] = (byte) chr; /* Add byte to buffer */
crc = CRC_16_L_STEP(crc, (word) chr); /* Update the CRC */
}
break;
/*- - - - - - - - - - - - - - - - - - -*/
default: /* Shouldn't happen with an enum, but for safety ... */
state = HDLC_HUNT_FOR_FLAG; /* Start over */
break;
}/* switch on state */
}/* for (packet not found) */
return len;
} /* rcv_packet() */
/*===========================================================================
FUNCTION write_cmd
DESCRIPTION
This function processes a write command packet. Pending a valid address
range, the data is written to RAM. Note that an offset needs to be added
to the address to move it to the target RAM location. The Intel MCS86 hex
file format does not support the address range for the ARM, therefore, it
is created with an implicit start address of 0, which then needs to be
offset into the intended address range.
DEPENDENCIES
None.
RETURN VALUE
None.
SIDE EFFECTS
None.
===========================================================================*/
static void write_cmd
(
byte *cmd_buf,
/* Pointer to the received command packet */
word cmd_len
/* Number of bytes received in the command packet */
)
{
dword addr; /* destination address for write */
byte *w_addr; /* offset address */
byte *start; /* start location for write - includes offset */
byte *data; /* pointer to bytes of data */
word len; /* number of bytes to write */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
if (cmd_len < WRITE_SIZ) /* Make sure at least the header arrived */
{
transmit_response(NAK_EARLY_END); /* Nope, packet ended early */
return;
}
/* Verify that a valid security code was previously received */
if (!sec_code_unlocked)
{
transmit_response(NAK_NO_SEC_CODE); /* It wasn't, so complain */
return;
}
B_PTR(addr)[3] = 0; /* Extract destination address from packet */
B_PTR(addr)[2] = cmd_buf[1];
B_PTR(addr)[1] = cmd_buf[2];
B_PTR(addr)[0] = cmd_buf[3];
B_PTR(len)[1] = cmd_buf[4]; /* Extract write length from packet */
B_PTR(len)[0] = cmd_buf[5];
if (len + WRITE_SIZ != cmd_len) /* Packet must be exactly the right len */
{
transmit_response(NAK_INVALID_LEN); /* It wasn't, so complain */
return;
}
/* convert addresses to RAM address range */
w_addr = (byte *) (addr+DLOAD_OFFSET);
start = (byte *) (addr+DLOAD_OFFSET);
/* check address range limits */
if (w_addr < (byte*)DLOAD_BASE || (w_addr+len) >= (byte*)DLOAD_LIMIT)
{
transmit_response(NAK_INVALID_DEST);
return;
}
/* start of data portion of packet */
data = (byte *) (cmd_buf+6);
/* perform the write to memory */
while (w_addr <= (start + len)) {
*w_addr++ = *data++;
}
/* everything ok */
transmit_response(ACK);
} /* write_cmd() */
/*===========================================================================
FUNCTION erase_cmd
DESCRIPTION
This function processes an erase command packet. Pending a valid address
range, the specified area is erased from RAM. Note that an offset needs to be added
to the address to move it to the target RAM location. The Intel MCS86 hex
file format does not support the address range for the ARM, therefore, it
is created with an implicit start address of 0, which then needs to be
offset into the intended address range.
DEPENDENCIES
None.
RETURN VALUE
None.
SIDE EFFECTS
None.
===========================================================================*/
static void erase_cmd
(
byte *cmd_buf,
/* Pointer to the received command packet */
word cmd_len
/* Number of bytes received in the command packet */
)
{
dword addr; /* destination address */
dword len; /* number of bytes to erase */
byte *e_addr; /* offset address */
byte *start; /* start location for erase */
byte *data; /* pointer to bytes of data */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
if (cmd_len != ERASE_SIZ) /* Make sure the whole packet arrived */
{
transmit_response(NAK_EARLY_END); /* Nope, packet ended early */
return;
}
/* Verify that a valid security code was previously received */
if (!sec_code_unlocked)
{
transmit_response(NAK_NO_SEC_CODE); /* It wasn't, so complain */
return;
}
B_PTR(addr)[3] = 0; /* Extract destination address from packet */
B_PTR(addr)[2] = cmd_buf[1];
B_PTR(addr)[1] = cmd_buf[2];
B_PTR(addr)[0] = cmd_buf[3];
B_PTR(len)[3] = 0; /* Extract write length from packet */
B_PTR(len)[2] = cmd_buf[4];
B_PTR(len)[1] = cmd_buf[5];
B_PTR(len)[0] = cmd_buf[6];
/* convert addresses to RAM address range */
e_addr = (byte *) (addr+DLOAD_OFFSET);
start = (byte *) (addr+DLOAD_OFFSET);
/* check address range limits */
if (e_addr < (byte*)DLOAD_BASE || (e_addr+len) >= (byte*)DLOAD_LIMIT)
{
transmit_response(NAK_INVALID_DEST);
}
/* start of data portion of packet */
data = (byte *) (cmd_buf+6);
/* erase the memory */
while (e_addr <= (start + len)) {
*e_addr++ = 0x00;
}
/* everything ok */
transmit_response(ACK);
} /* erase_cmd() */
/*===========================================================================
FUNCTION go_cmd
DESCRIPTION
This function processes a GO command packet, which requires the
transfer of execution control to a specified address.
DEPENDENCIES
None.
RETURN VALUE
Generally, this function does not return, since the entry point of
the downloaded module is not supposed to return. However, if the
called code does return, this function returns (void).
SIDE EFFECTS
None.
===========================================================================*/
static void go_cmd
(
byte *cmd_buf,
/* Pointer to the received command packet */
word cmd_len
/* Number of bytes received in the command packet */
)
{
void (* jump_point)(void); /* address of the routine to run */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Make sure the whole packet arrived. */
if (cmd_len != GO_SIZ)
{
transmit_response(NAK_EARLY_END); /* Nope, packet ended early */
return;
}
/* Verify that a valid security code was previously received */
if (!sec_code_unlocked)
{
transmit_response(NAK_NO_SEC_CODE); /* It wasn't, so complain */
return;
}
/* Construct a pointer to the destination address */
B_PTR(jump_point)[3] = cmd_buf[1]; /* Extract code segment from packet */
B_PTR(jump_point)[2] = cmd_buf[2];
B_PTR(jump_point)[1] = cmd_buf[3]; /* Extract code offset from packet */
B_PTR(jump_point)[0] = cmd_buf[4];
transmit_response(ACK); /* Have to send the ACK before GOing. */
uart_drain(); /* Make sure the response gets out */
jump_point(); /* Call the routine */
/* It really shouldn't return, but just in case it does we will
continue with packet processing and hope everything is still
properly set up for that. */
} /* go_cmd() */
/*============================================================================
FUNCTION UNLOCK_CMD
DESCRIPTION
Process an unlock command.
If the security code contained in the unlock command does not match
the security code stored in flash memory, the phone will be
powered-down. If the codes do match, then secure download functions
will be unlocked.
FORMAL ARGUMENTS
None
DEPENDENCIES
None
RETURN VALUE
An error flag is returned: zero indicates no errors occurred,
one indicates that an error did occur. However, if an incorrect
security code is contained in the unlock command, the phone will
be powered-down and this function will not return.
SIDE EFFECTS
None
============================================================================*/
static void unlock_cmd
(
byte *cmd_buf,
/* Pointer to the received command packet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -