1/*
2 * Copyright (c) 2014-2023 Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
8#include <asm_macros.S>
9#include <common/debug.h>
10
11	.globl	asm_print_str
12	.globl	asm_print_hex
13	.globl	asm_print_hex_bits
14	.globl	asm_print_newline
15	.globl	asm_assert
16	.globl	el3_panic
17	.globl	elx_panic
18
19/* Since the max decimal input number is 65536 */
20#define MAX_DEC_DIVISOR		10000
21/* The offset to add to get ascii for numerals '0 - 9' */
22#define ASCII_OFFSET_NUM	0x30
23
24#if ENABLE_ASSERTIONS
25.section .rodata.assert_str, "aS"
26assert_msg1:
27	.asciz "ASSERT: File "
28assert_msg2:
29	.asciz " Line "
30
31	/*
32	 * This macro is intended to be used to print the
33	 * line number in decimal. Used by asm_assert macro.
34	 * The max number expected is 65536.
35	 * In: x4 = the decimal to print.
36	 * Clobber: x30, x0, x1, x2, x5, x6
37	 */
38	.macro asm_print_line_dec
39	mov	x6, #10		/* Divide by 10 after every loop iteration */
40	mov	x5, #MAX_DEC_DIVISOR
41dec_print_loop:
42	udiv	x0, x4, x5			/* Get the quotient */
43	msub	x4, x0, x5, x4			/* Find the remainder */
44	add	x0, x0, #ASCII_OFFSET_NUM	/* Convert to ascii */
45	bl	plat_crash_console_putc
46	udiv	x5, x5, x6			/* Reduce divisor */
47	cbnz	x5, dec_print_loop
48	.endm
49
50
51/* ---------------------------------------------------------------------------
52 * Assertion support in assembly.
53 * The below function helps to support assertions in assembly where we do not
54 * have a C runtime stack. Arguments to the function are :
55 * x0 - File name
56 * x1 - Line no
57 * Clobber list : x30, x0, x1, x2, x3, x4, x5, x6.
58 * ---------------------------------------------------------------------------
59 */
60func asm_assert
61#if LOG_LEVEL >= LOG_LEVEL_INFO
62	/*
63	 * Only print the output if LOG_LEVEL is higher or equal to
64	 * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1.
65	 */
66	mov	x5, x0
67	mov	x6, x1
68
69	/* Ensure the console is initialized */
70	bl	plat_crash_console_init
71
72	/* Check if the console is initialized */
73	cbz	x0, _assert_loop
74
75	/* The console is initialized */
76	adr	x4, assert_msg1
77	bl	asm_print_str
78	mov	x4, x5
79	bl	asm_print_str
80	adr	x4, assert_msg2
81	bl	asm_print_str
82
83	/* Check if line number higher than max permitted */
84	tst	x6, #~0xffff
85	b.ne	_assert_loop
86	mov	x4, x6
87	asm_print_line_dec
88	bl	plat_crash_console_flush
89_assert_loop:
90#endif /* LOG_LEVEL >= LOG_LEVEL_INFO */
91	no_ret	plat_panic_handler
92endfunc asm_assert
93#endif /* ENABLE_ASSERTIONS */
94
95/*
96 * This function prints a string from address in x4.
97 * In: x4 = pointer to string.
98 * Clobber: x30, x0, x1, x2, x3
99 */
100func asm_print_str
101	mov	x3, x30
1021:
103	ldrb	w0, [x4], #0x1
104	cbz	x0, 2f
105	bl	plat_crash_console_putc
106	b	1b
1072:
108	ret	x3
109endfunc asm_print_str
110
111/*
112 * This function prints a hexadecimal number in x4.
113 * In: x4 = the hexadecimal to print.
114 * Clobber: x30, x0 - x3, x5
115 */
116func asm_print_hex
117	mov	x5, #64  /* No of bits to convert to ascii */
118
119	/* Convert to ascii number of bits in x5 */
120asm_print_hex_bits:
121	mov	x3, x30
1221:
123	sub	x5, x5, #4
124	lsrv	x0, x4, x5
125	and	x0, x0, #0xf
126	cmp	x0, #0xA
127	b.lo	2f
128	/* Add by 0x27 in addition to ASCII_OFFSET_NUM
129	 * to get ascii for characters 'a - f'.
130	 */
131	add	x0, x0, #0x27
1322:
133	add	x0, x0, #ASCII_OFFSET_NUM
134	bl	plat_crash_console_putc
135	cbnz	x5, 1b
136	ret	x3
137endfunc asm_print_hex
138
139/*
140 * Helper function to print newline to console
141 * Clobber: x0
142 */
143func asm_print_newline
144	mov	x0, '\n'
145	b	plat_crash_console_putc
146endfunc asm_print_newline
147
148	/***********************************************************
149	 * The common implementation of el3_panic for all BL stages
150	 ***********************************************************/
151
152.section .rodata.panic_str, "aS"
153	panic_msg: .asciz "PANIC at PC : 0x"
154
155func elx_panic
156#if CRASH_REPORTING && defined(IMAGE_BL31)
157	b	report_elx_panic
158#endif /* CRASH_REPORTING && IMAGE_BL31 */
159
160	b	panic_common
161endfunc elx_panic
162
163/* ---------------------------------------------------------------------------
164 * el3_panic assumes that it is invoked from a C Runtime Environment ie a
165 * valid stack exists. This call will not return.
166 * Clobber list : if CRASH_REPORTING is not enabled then x30, x0 - x6
167 * ---------------------------------------------------------------------------
168 */
169
170func el3_panic
171#if CRASH_REPORTING && defined(IMAGE_BL31)
172	b	report_el3_panic
173#endif /* CRASH_REPORTING && IMAGE_BL31 */
174
175panic_common:
176	mov	x6, x30
177	bl	plat_crash_console_init
178
179	/* Check if the console is initialized */
180	cbz	x0, _panic_handler
181
182	/* The console is initialized */
183	adr	x4, panic_msg
184	bl	asm_print_str
185	mov	x4, x6
186
187	/* The panic location is lr -4 */
188	sub	x4, x4, #4
189	bl	asm_print_hex
190
191	/* Print new line */
192	bl	asm_print_newline
193
194	bl	plat_crash_console_flush
195
196_panic_handler:
197	/* Pass to plat_panic_handler the address from where el3_panic was
198	 * called, not the address of the call from el3_panic. */
199	mov	x30, x6
200	b	plat_panic_handler
201
202endfunc el3_panic
203