[PATCH u-boot-marvell 5/5] tools: kwboot: Do not use stack when setting baudrate back to default value

Stefan Roese sr at denx.de
Wed Nov 3 06:38:42 CET 2021


On 27.10.21 20:57, Marek Behún wrote:
> From: Pali Rohár <pali at kernel.org>
> 
> The ARM code we inject into the image to change baudrate back to the
> default value of 115200 Baud, which is run after successful UART transfer
> of the whole image, cannot use stack as at this stage stack pointer is not
> initialized yet.
> 
> Stack can only be used when BootROM is executing binary header, to
> preserve state of registers, since BootROM expects that.
> 
> Change the ARM baudrate code to not use stack at all and put binary
> header specific pre + post code (which stores and restores registers) into
> separate arrays.
> 
> The baudrate change code now jumps at it's end and expects that there is
> either code which returns to the BootROM or jumps to the original exec
> address.
> 
> Signed-off-by: Pali Rohár <pali at kernel.org>
> Reviewed-by: Marek Behún <marek.behun at nic.cz>

Reviewed-by: Stefan Roese <sr at denx.de>

Thanks,
Stefan

> ---
>   tools/kwboot.c | 112 ++++++++++++++++++++++++++++---------------------
>   1 file changed, 65 insertions(+), 47 deletions(-)
> 
> diff --git a/tools/kwboot.c b/tools/kwboot.c
> index 62c218ef64..359b43c0d8 100644
> --- a/tools/kwboot.c
> +++ b/tools/kwboot.c
> @@ -78,14 +78,7 @@ struct kwboot_block {
>   #define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */
>   #define KWBOOT_HDR_RSP_TIMEO 10000 /* ms */
>   
> -/* ARM code making baudrate changing function return to original exec address */
> -static unsigned char kwboot_pre_baud_code[] = {
> -				/* exec_addr:                                 */
> -	0x00, 0x00, 0x00, 0x00, /* .word 0                                    */
> -	0x0c, 0xe0, 0x1f, 0xe5, /* ldr lr, exec_addr                          */
> -};
> -
> -/* ARM code for binary header injection to change baudrate */
> +/* ARM code to change baudrate */
>   static unsigned char kwboot_baud_code[] = {
>   				/* ; #define UART_BASE 0xd0012000             */
>   				/* ; #define THR       0x00                   */
> @@ -123,14 +116,12 @@ static unsigned char kwboot_baud_code[] = {
>   				/* ;   return 0;                              */
>   				/* ; }                                        */
>   
> -	0xfe, 0x5f, 0x2d, 0xe9, /* push  { r1 - r12, lr }                     */
> -
>   				/*  ; r0 = UART_BASE                          */
>   	0x0d, 0x02, 0xa0, 0xe3, /* mov   r0, #0xd0000000                      */
>   	0x12, 0x0a, 0x80, 0xe3, /* orr   r0, r0, #0x12000                     */
>   
>   				/*  ; r2 = address of preamble string         */
> -	0xcc, 0x20, 0x8f, 0xe2, /* adr   r2, preamble                         */
> +	0xc8, 0x20, 0x8f, 0xe2, /* adr   r2, preamble                         */
>   
>   				/*  ; Send preamble string over UART          */
>   				/* .Lloop_preamble:                           */
> @@ -177,7 +168,7 @@ static unsigned char kwboot_baud_code[] = {
>   
>   				/*  ; Read old baudrate value                 */
>   				/*  ; r2 = old_baudrate                       */
> -	0x88, 0x20, 0x9f, 0xe5, /* ldr   r2, old_baudrate                     */
> +	0x84, 0x20, 0x9f, 0xe5, /* ldr   r2, old_baudrate                     */
>   
>   				/*  ; Calculate base clock                    */
>   				/*  ; r1 = r2 * r1                            */
> @@ -185,7 +176,7 @@ static unsigned char kwboot_baud_code[] = {
>   
>   				/*  ; Read new baudrate value                 */
>   				/*  ; r2 = new_baudrate                       */
> -	0x84, 0x20, 0x9f, 0xe5, /* ldr   r2, new_baudrate                     */
> +	0x80, 0x20, 0x9f, 0xe5, /* ldr   r2, new_baudrate                     */
>   
>   				/*  ; Calculate new Divisor Latch             */
>   				/*  ; r1 = DIV_ROUND(r1, r2) =                */
> @@ -234,9 +225,7 @@ static unsigned char kwboot_baud_code[] = {
>   	0x00, 0x00, 0x51, 0xe3, /* cmp   r1, #0                               */
>   	0xfc, 0xff, 0xff, 0x1a, /* bne   .Lloop_sleep                         */
>   
> -				/*  ; Return 0 - no error                     */
> -	0x00, 0x00, 0xa0, 0xe3, /* mov   r0, #0                               */
> -	0xfe, 0x9f, 0xbd, 0xe8, /* pop   { r1 - r12, pc }                     */
> +	0x05, 0x00, 0x00, 0xea, /* b     end                                  */
>   
>   				/*  ; Preamble string                         */
>   				/* preamble:                                  */
> @@ -252,10 +241,29 @@ static unsigned char kwboot_baud_code[] = {
>   				/*  ; Placeholder for new baudrate value      */
>   				/* new_baudrate:                              */
>   	0x00, 0x00, 0x00, 0x00, /* .word 0                                    */
> +
> +				/* end:                                       */
> +};
> +
> +/* ARM code for storing registers for future returning back to the bootrom */
> +static unsigned char kwboot_baud_code_binhdr_pre[] = {
> +	0xfe, 0x5f, 0x2d, 0xe9, /* push  { r1 - r12, lr }                     */
>   };
>   
> -#define KWBOOT_BAUDRATE_BIN_HEADER_SZ (sizeof(kwboot_baud_code) + \
> -				       sizeof(struct opt_hdr_v1) + 8 + 16)
> +/* ARM code for returning back to the bootrom */
> +static unsigned char kwboot_baud_code_binhdr_post[] = {
> +				/*  ; Return 0 - no error                     */
> +	0x00, 0x00, 0xa0, 0xe3, /* mov   r0, #0                               */
> +	0xfe, 0x9f, 0xbd, 0xe8, /* pop   { r1 - r12, pc }                     */
> +};
> +
> +/* ARM code for jumping to the original image exec_addr */
> +static unsigned char kwboot_baud_code_data_jump[] = {
> +	0x04, 0xf0, 0x1f, 0xe5, /* ldr   pc, exec_addr                        */
> +				/*  ; Placeholder for exec_addr               */
> +				/* exec_addr:                                 */
> +	0x00, 0x00, 0x00, 0x00, /* .word 0                                    */
> +};
>   
>   static const char kwb_baud_magic[16] = "$baudratechange";
>   
> @@ -1409,44 +1417,51 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz)
>   }
>   
>   static void
> -_inject_baudrate_change_code(void *img, size_t *size, int pre,
> +_inject_baudrate_change_code(void *img, size_t *size, int for_data,
>   			     int old_baud, int new_baud)
>   {
> -	uint32_t codesz = sizeof(kwboot_baud_code);
>   	struct main_hdr_v1 *hdr = img;
> +	uint32_t orig_datasz;
> +	uint32_t codesz;
>   	uint8_t *code;
>   
> -	if (pre) {
> -		uint32_t presz = sizeof(kwboot_pre_baud_code);
> -		uint32_t orig_datasz;
> -
> +	if (for_data) {
>   		orig_datasz = le32_to_cpu(hdr->blocksize) - sizeof(uint32_t);
>   
> -		code = kwboot_img_grow_data_right(img, size, presz + codesz);
> -
> -		/*
> -		 * We need to prepend code that loads lr register with original
> -		 * value of hdr->execaddr. We do this by putting the original
> -		 * exec address before the code that loads it relatively from
> -		 * it's beginning.
> -		 * Afterwards we change the exec address to this code (which is
> -		 * at offset 4, because the first 4 bytes contain the original
> -		 * exec address).
> -		 */
> -		memcpy(code, kwboot_pre_baud_code, presz);
> -		*(uint32_t *)code = hdr->execaddr;
> -
> -		hdr->execaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) +
> -					    orig_datasz + 4);
> -
> -		code += presz;
> +		codesz = sizeof(kwboot_baud_code) +
> +			 sizeof(kwboot_baud_code_data_jump);
> +		code = kwboot_img_grow_data_right(img, size, codesz);
>   	} else {
> +		codesz = sizeof(kwboot_baud_code_binhdr_pre) +
> +			 sizeof(kwboot_baud_code) +
> +			 sizeof(kwboot_baud_code_binhdr_post);
>   		code = kwboot_add_bin_ohdr_v1(img, size, codesz);
> +
> +		codesz = sizeof(kwboot_baud_code_binhdr_pre);
> +		memcpy(code, kwboot_baud_code_binhdr_pre, codesz);
> +		code += codesz;
>   	}
>   
> -	memcpy(code, kwboot_baud_code, codesz - 8);
> -	*(uint32_t *)(code + codesz - 8) = cpu_to_le32(old_baud);
> -	*(uint32_t *)(code + codesz - 4) = cpu_to_le32(new_baud);
> +	codesz = sizeof(kwboot_baud_code) - 2 * sizeof(uint32_t);
> +	memcpy(code, kwboot_baud_code, codesz);
> +	code += codesz;
> +	*(uint32_t *)code = cpu_to_le32(old_baud);
> +	code += sizeof(uint32_t);
> +	*(uint32_t *)code = cpu_to_le32(new_baud);
> +	code += sizeof(uint32_t);
> +
> +	if (for_data) {
> +		codesz = sizeof(kwboot_baud_code_data_jump) - sizeof(uint32_t);
> +		memcpy(code, kwboot_baud_code_data_jump, codesz);
> +		code += codesz;
> +		*(uint32_t *)code = hdr->execaddr;
> +		code += sizeof(uint32_t);
> +		hdr->execaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) + orig_datasz);
> +	} else {
> +		codesz = sizeof(kwboot_baud_code_binhdr_post);
> +		memcpy(code, kwboot_baud_code_binhdr_post, codesz);
> +		code += codesz;
> +	}
>   }
>   
>   static int
> @@ -1729,10 +1744,13 @@ main(int argc, char **argv)
>   		baudrate = 0;
>   	else
>   		/* ensure we have enough space for baudrate change code */
> -		after_img_rsv += KWBOOT_BAUDRATE_BIN_HEADER_SZ +
> +		after_img_rsv += sizeof(struct opt_hdr_v1) + 8 + 16 +
> +				 sizeof(kwboot_baud_code_binhdr_pre) +
> +				 sizeof(kwboot_baud_code) +
> +				 sizeof(kwboot_baud_code_binhdr_post) +
>   				 KWBOOT_XM_BLKSZ +
> -				 sizeof(kwboot_pre_baud_code) +
>   				 sizeof(kwboot_baud_code) +
> +				 sizeof(kwboot_baud_code_data_jump) +
>   				 KWBOOT_XM_BLKSZ;
>   
>   	if (imgpath) {
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de


More information about the U-Boot mailing list