diff options
Diffstat (limited to 'include/lib/cpus/aarch32/cpu_macros.S')
-rw-r--r-- | include/lib/cpus/aarch32/cpu_macros.S | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S new file mode 100644 index 0000000..096e0b1 --- /dev/null +++ b/include/lib/cpus/aarch32/cpu_macros.S @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef CPU_MACROS_S +#define CPU_MACROS_S + +#include <lib/cpus/cpu_ops.h> +#include <lib/cpus/errata.h> + + /* + * Write given expressions as words + * + * _count: + * Write at least _count words. If the given number of expressions + * is less than _count, repeat the last expression to fill _count + * words in total + * _rest: + * Optional list of expressions. _this is for parameter extraction + * only, and has no significance to the caller + * + * Invoked as: + * fill_constants 2, foo, bar, blah, ... + */ + .macro fill_constants _count:req, _this, _rest:vararg + .ifgt \_count + /* Write the current expression */ + .ifb \_this + .error "Nothing to fill" + .endif + .word \_this + + /* Invoke recursively for remaining expressions */ + .ifnb \_rest + fill_constants \_count-1, \_rest + .else + fill_constants \_count-1, \_this + .endif + .endif + .endm + + /* + * Declare CPU operations + * + * _name: + * Name of the CPU for which operations are being specified + * _midr: + * Numeric value expected to read from CPU's MIDR + * _resetfunc: + * Reset function for the CPU. If there's no CPU reset function, + * specify CPU_NO_RESET_FUNC + * _power_down_ops: + * Comma-separated list of functions to perform power-down + * operatios on the CPU. At least one, and up to + * CPU_MAX_PWR_DWN_OPS number of functions may be specified. + * Starting at power level 0, these functions shall handle power + * down at subsequent power levels. If there aren't exactly + * CPU_MAX_PWR_DWN_OPS functions, the last specified one will be + * used to handle power down at subsequent levels + */ + .macro declare_cpu_ops _name:req, _midr:req, _resetfunc:req, \ + _power_down_ops:vararg + .section .cpu_ops, "a" + .align 2 + .type cpu_ops_\_name, %object + .word \_midr +#if defined(IMAGE_AT_EL3) + .word \_resetfunc +#endif +#ifdef IMAGE_BL32 + /* Insert list of functions */ + fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops +#endif + + /* + * It is possible (although unlikely) that a cpu may have no errata in + * code. In that case the start label will not be defined. The list is + * inteded to be used in a loop, so define it as zero-length for + * predictable behaviour. Since this macro is always called at the end + * of the cpu file (after all errata have been parsed) we can be sure + * that we are at the end of the list. Some cpus call the macro twice, + * so only do this once. + */ + .pushsection .rodata.errata_entries + .ifndef \_name\()_errata_list_start + \_name\()_errata_list_start: + .endif + /* some call this multiple times, so only do this once */ + .ifndef \_name\()_errata_list_end + \_name\()_errata_list_end: + .endif + .popsection + + /* and now put them in cpu_ops */ + .word \_name\()_errata_list_start + .word \_name\()_errata_list_end + +#if REPORT_ERRATA + .ifndef \_name\()_cpu_str + /* + * Place errata reported flag, and the spinlock to arbitrate access to + * it in the data section. + */ + .pushsection .data + define_asm_spinlock \_name\()_errata_lock + \_name\()_errata_reported: + .word 0 + .popsection + + /* Place CPU string in rodata */ + .pushsection .rodata + \_name\()_cpu_str: + .asciz "\_name" + .popsection + .endif + + /* + * Mandatory errata status printing function for CPUs of + * this class. + */ + .word \_name\()_errata_report + .word \_name\()_cpu_str + +#ifdef IMAGE_BL32 + /* Pointers to errata lock and reported flag */ + .word \_name\()_errata_lock + .word \_name\()_errata_reported +#endif +#endif + .endm + +#if REPORT_ERRATA + /* + * Print status of a CPU errata + * + * _chosen: + * Identifier indicating whether or not a CPU errata has been + * compiled in. + * _cpu: + * Name of the CPU + * _id: + * Errata identifier + * _rev_var: + * Register containing the combined value CPU revision and variant + * - typically the return value of cpu_get_rev_var + */ + .macro report_errata _chosen, _cpu, _id, _rev_var=r4 + /* Stash a string with errata ID */ + .pushsection .rodata + \_cpu\()_errata_\_id\()_str: + .asciz "\_id" + .popsection + + /* Check whether errata applies */ + mov r0, \_rev_var + bl check_errata_\_id + + .ifeq \_chosen + /* + * Errata workaround has not been compiled in. If the errata would have + * applied had it been compiled in, print its status as missing. + */ + cmp r0, #0 + movne r0, #ERRATA_MISSING + .endif + ldr r1, =\_cpu\()_cpu_str + ldr r2, =\_cpu\()_errata_\_id\()_str + bl errata_print_msg + .endm +#endif + /* + * Helper macro that reads the part number of the current CPU and jumps + * to the given label if it matches the CPU MIDR provided. + * + * Clobbers: r0-r1 + */ + .macro jump_if_cpu_midr _cpu_midr, _label + ldcopr r0, MIDR + ubfx r0, r0, #MIDR_PN_SHIFT, #12 + ldr r1, =((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK) + cmp r0, r1 + beq \_label + .endm + +/* + * NOTE an erratum and CVE id could clash. However, both numbers are very large + * and the probablity is minuscule. Working around this makes code very + * complicated and extremely difficult to read so it is not considered. In the + * unlikely event that this does happen, prepending the CVE id with a 0 should + * resolve the conflict + */ + +/* + * Add an entry for this erratum to the errata framework + * + * _cpu: + * Name of cpu as given to declare_cpu_ops + * + * _cve: + * Whether erratum is a CVE. CVE year if yes, 0 otherwise + * + * _id: + * Erratum or CVE number. Please combine with the previous field with the + * ERRATUM or CVE macros + * + * _chosen: + * Compile time flag on whether the erratum is included + * + * _special: + * The special non-standard name of an erratum + */ +.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _special + .pushsection .rodata.errata_entries + .align 2 + .ifndef \_cpu\()_errata_list_start + \_cpu\()_errata_list_start: + .endif + + /* unused on AArch32, maintain for portability */ + .word 0 + /* TODO(errata ABI): this prevents all checker functions from + * being optimised away. Can be done away with unless the ABI + * needs them */ + .ifnb \_special + .word check_errata_\_special + .elseif \_cve + .word check_errata_cve_\_cve\()_\_id + .else + .word check_errata_\_id + .endif + /* Will fit CVEs with up to 10 character in the ID field */ + .word \_id + .hword \_cve + .byte \_chosen + /* TODO(errata ABI): mitigated field for known but unmitigated + * errata*/ + .byte 0x1 + .popsection +.endm + +/* + * Maintain compatibility with the old scheme of "each cpu has its own reporter". + * TODO remove entirely once all cpus have been converted. This includes the + * cpu_ops entry, as print_errata_status can call this directly for all cpus + */ +.macro errata_report_shim _cpu:req + #if REPORT_ERRATA + func \_cpu\()_errata_report + push {r12, lr} + + bl generic_errata_report + + pop {r12, lr} + bx lr + endfunc \_cpu\()_errata_report + #endif +.endm +#endif /* CPU_MACROS_S */ |