123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #ifndef CPU_MACROS_S
- #define CPU_MACROS_S
- #include <assert_macros.S>
- #include <lib/cpus/cpu_ops.h>
- #include <lib/cpus/errata.h>
- /*
- * Write given expressions as quad words
- *
- * _count:
- * Write at least _count quad words. If the given number of
- * expressions is less than _count, repeat the last expression to
- * fill _count quad 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
- .quad \_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
- * _extra1:
- * This is a placeholder for future per CPU operations. Currently,
- * some CPUs use this entry to set a test function to determine if
- * the workaround for CVE-2017-5715 needs to be applied or not.
- * _extra2:
- * This is a placeholder for future per CPU operations. Currently
- * some CPUs use this entry to set a function to disable the
- * workaround for CVE-2018-3639.
- * _extra3:
- * This is a placeholder for future per CPU operations. Currently,
- * some CPUs use this entry to set a test function to determine if
- * the workaround for CVE-2022-23960 needs to be applied or not.
- * _e_handler:
- * This is a placeholder for future per CPU exception handlers.
- * _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_base _name:req, _midr:req, _resetfunc:req, \
- _extra1:req, _extra2:req, _extra3:req, _e_handler:req, _power_down_ops:vararg
- .section .cpu_ops, "a"
- .align 3
- .type cpu_ops_\_name, %object
- .quad \_midr
- #if defined(IMAGE_AT_EL3)
- .quad \_resetfunc
- #endif
- .quad \_extra1
- .quad \_extra2
- .quad \_extra3
- .quad \_e_handler
- #ifdef IMAGE_BL31
- /* 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
- * intended 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 declare_cpu_ops
- * twice, so only do this once.
- */
- .pushsection .rodata.errata_entries
- .ifndef \_name\()_errata_list_start
- \_name\()_errata_list_start:
- .endif
- .ifndef \_name\()_errata_list_end
- \_name\()_errata_list_end:
- .endif
- .popsection
- /* and now put them in cpu_ops */
- .quad \_name\()_errata_list_start
- .quad \_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
- .quad \_name\()_cpu_str
- #ifdef IMAGE_BL31
- /* Pointers to errata lock and reported flag */
- .quad \_name\()_errata_lock
- .quad \_name\()_errata_reported
- #endif /* IMAGE_BL31 */
- #endif /* REPORT_ERRATA */
- #if defined(IMAGE_BL31) && CRASH_REPORTING
- .quad \_name\()_cpu_reg_dump
- #endif
- .endm
- .macro declare_cpu_ops _name:req, _midr:req, _resetfunc:req, \
- _power_down_ops:vararg
- declare_cpu_ops_base \_name, \_midr, \_resetfunc, 0, 0, 0, 0, \
- \_power_down_ops
- .endm
- .macro declare_cpu_ops_eh _name:req, _midr:req, _resetfunc:req, \
- _e_handler:req, _power_down_ops:vararg
- declare_cpu_ops_base \_name, \_midr, \_resetfunc, \
- 0, 0, 0, \_e_handler, \_power_down_ops
- .endm
- .macro declare_cpu_ops_wa _name:req, _midr:req, \
- _resetfunc:req, _extra1:req, _extra2:req, \
- _extra3:req, _power_down_ops:vararg
- declare_cpu_ops_base \_name, \_midr, \_resetfunc, \
- \_extra1, \_extra2, \_extra3, 0, \_power_down_ops
- .endm
- /*
- * This macro is used on some CPUs to detect if they are vulnerable
- * to CVE-2017-5715.
- */
- .macro cpu_check_csv2 _reg _label
- mrs \_reg, id_aa64pfr0_el1
- ubfx \_reg, \_reg, #ID_AA64PFR0_CSV2_SHIFT, #ID_AA64PFR0_CSV2_LENGTH
- /*
- * If the field equals 1, branch targets trained in one context cannot
- * affect speculative execution in a different context.
- *
- * If the field equals 2, it means that the system is also aware of
- * SCXTNUM_ELx register contexts. We aren't using them in the TF, so we
- * expect users of the registers to do the right thing.
- *
- * Only apply mitigations if the value of this field is 0.
- */
- #if ENABLE_ASSERTIONS
- cmp \_reg, #3 /* Only values 0 to 2 are expected */
- ASM_ASSERT(lo)
- #endif
- cmp \_reg, #0
- bne \_label
- .endm
- /*
- * 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 x0.
- */
- .macro jump_if_cpu_midr _cpu_midr, _label
- mrs x0, midr_el1
- ubfx x0, x0, MIDR_PN_SHIFT, #12
- cmp w0, #((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
- b.eq \_label
- .endm
- /*
- * Workaround wrappers for errata that apply at reset or runtime. Reset errata
- * will be applied automatically
- *
- * _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 previous field with ERRATUM
- * or CVE macros
- *
- * _chosen:
- * Compile time flag on whether the erratum is included
- *
- * _apply_at_reset:
- * Whether the erratum should be automatically applied at reset
- */
- .macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
- .pushsection .rodata.errata_entries
- .align 3
- .ifndef \_cpu\()_errata_list_start
- \_cpu\()_errata_list_start:
- .endif
- /* check if unused and compile out if no references */
- .if \_apply_at_reset && \_chosen
- .quad erratum_\_cpu\()_\_id\()_wa
- .else
- .quad 0
- .endif
- /* TODO(errata ABI): this prevents all checker functions from
- * being optimised away. Can be done away with unless the ABI
- * needs them */
- .quad check_erratum_\_cpu\()_\_id
- /* 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
- .macro _workaround_start _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
- add_erratum_entry \_cpu, \_cve, \_id, \_chosen, \_apply_at_reset
- func erratum_\_cpu\()_\_id\()_wa
- mov x8, x30
- /* save rev_var for workarounds that might need it but don't
- * restore to x0 because few will care */
- mov x7, x0
- bl check_erratum_\_cpu\()_\_id
- cbz x0, erratum_\_cpu\()_\_id\()_skip
- .endm
- .macro _workaround_end _cpu:req, _id:req
- erratum_\_cpu\()_\_id\()_skip:
- ret x8
- endfunc erratum_\_cpu\()_\_id\()_wa
- .endm
- /*******************************************************************************
- * Errata workaround wrappers
- ******************************************************************************/
- /*
- * Workaround wrappers for errata that apply at reset or runtime. Reset errata
- * will be applied automatically
- *
- * _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 previous field with ERRATUM
- * or CVE macros
- *
- * _chosen:
- * Compile time flag on whether the erratum is included
- *
- * in body:
- * clobber x0 to x7 (please only use those)
- * argument x7 - cpu_rev_var
- *
- * _wa clobbers: x0-x8 (PCS compliant)
- */
- .macro workaround_reset_start _cpu:req, _cve:req, _id:req, _chosen:req
- _workaround_start \_cpu, \_cve, \_id, \_chosen, 1
- .endm
- /*
- * See `workaround_reset_start` for usage info. Additional arguments:
- *
- * _midr:
- * Check if CPU's MIDR matches the CPU it's meant for. Must be specified
- * for errata applied in generic code
- */
- .macro workaround_runtime_start _cpu:req, _cve:req, _id:req, _chosen:req, _midr
- /*
- * Let errata specify if they need MIDR checking. Sadly, storing the
- * MIDR in an .equ to retrieve automatically blows up as it stores some
- * brackets in the symbol
- */
- .ifnb \_midr
- jump_if_cpu_midr \_midr, 1f
- b erratum_\_cpu\()_\_id\()_skip
- 1:
- .endif
- _workaround_start \_cpu, \_cve, \_id, \_chosen, 0
- .endm
- /*
- * Usage and arguments identical to `workaround_reset_start`. The _cve argument
- * is kept here so the same #define can be used as that macro
- */
- .macro workaround_reset_end _cpu:req, _cve:req, _id:req
- _workaround_end \_cpu, \_id
- .endm
- /*
- * See `workaround_reset_start` for usage info. The _cve argument is kept here
- * so the same #define can be used as that macro. Additional arguments:
- *
- * _no_isb:
- * Optionally do not include the trailing isb. Please disable with the
- * NO_ISB macro
- */
- .macro workaround_runtime_end _cpu:req, _cve:req, _id:req, _no_isb
- /*
- * Runtime errata do not have a reset function to call the isb for them
- * and missing the isb could be very problematic. It is also likely as
- * they tend to be scattered in generic code.
- */
- .ifb \_no_isb
- isb
- .endif
- _workaround_end \_cpu, \_id
- .endm
- /*******************************************************************************
- * Errata workaround helpers
- ******************************************************************************/
- /*
- * Set a bit in a system register. Can set multiple bits but is limited by the
- * way the ORR instruction encodes them.
- *
- * _reg:
- * Register to write to
- *
- * _bit:
- * Bit to set. Please use a descriptive #define
- *
- * _assert:
- * Optionally whether to read back and assert that the bit has been
- * written. Please disable with NO_ASSERT macro
- *
- * clobbers: x1
- */
- .macro sysreg_bit_set _reg:req, _bit:req, _assert=1
- mrs x1, \_reg
- orr x1, x1, #\_bit
- msr \_reg, x1
- .endm
- /*
- * Clear a bit in a system register. Can clear multiple bits but is limited by
- * the way the BIC instrucion encodes them.
- *
- * see sysreg_bit_set for usage
- */
- .macro sysreg_bit_clear _reg:req, _bit:req
- mrs x1, \_reg
- bic x1, x1, #\_bit
- msr \_reg, x1
- .endm
- .macro override_vector_table _table:req
- adr x1, \_table
- msr vbar_el3, x1
- .endm
- /*
- * BFI : Inserts bitfield into a system register.
- *
- * BFI{cond} Rd, Rn, #lsb, #width
- */
- .macro sysreg_bitfield_insert _reg:req, _src:req, _lsb:req, _width:req
- /* Source value for BFI */
- mov x1, #\_src
- mrs x0, \_reg
- bfi x0, x1, #\_lsb, #\_width
- msr \_reg, x0
- .endm
- .macro sysreg_bitfield_insert_from_gpr _reg:req, _gpr:req, _lsb:req, _width:req
- /* Source value in register for BFI */
- mov x1, \_gpr
- mrs x0, \_reg
- bfi x0, x1, #\_lsb, #\_width
- msr \_reg, x0
- .endm
- /*
- * Apply erratum
- *
- * _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 previous field with ERRATUM
- * or CVE macros
- *
- * _chosen:
- * Compile time flag on whether the erratum is included
- *
- * _get_rev:
- * Optional parameter that determines whether to insert a call to the CPU revision fetching
- * procedure. Stores the result of this in the temporary register x10 to allow for chaining
- *
- * clobbers: x0-x10 (PCS compliant)
- */
- .macro apply_erratum _cpu:req, _cve:req, _id:req, _chosen:req, _get_rev=GET_CPU_REV
- .if (\_chosen & \_get_rev)
- mov x9, x30
- bl cpu_get_rev_var
- mov x10, x0
- .elseif (\_chosen)
- mov x9, x30
- mov x0, x10
- .endif
- .if \_chosen
- bl erratum_\_cpu\()_\_id\()_wa
- mov x30, x9
- .endif
- .endm
- /*
- * Helpers to select which revisions errata apply to. Don't leave a link
- * register as the cpu_rev_var_*** will call the ret and we can save on one.
- *
- * _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 previous field with ERRATUM
- * or CVE macros
- *
- * _rev_num:
- * Revision to apply to
- *
- * in body:
- * clobber: x0 to x4
- * argument: x0 - cpu_rev_var
- */
- .macro check_erratum_ls _cpu:req, _cve:req, _id:req, _rev_num:req
- func check_erratum_\_cpu\()_\_id
- mov x1, #\_rev_num
- b cpu_rev_var_ls
- endfunc check_erratum_\_cpu\()_\_id
- .endm
- .macro check_erratum_hs _cpu:req, _cve:req, _id:req, _rev_num:req
- func check_erratum_\_cpu\()_\_id
- mov x1, #\_rev_num
- b cpu_rev_var_hs
- endfunc check_erratum_\_cpu\()_\_id
- .endm
- .macro check_erratum_range _cpu:req, _cve:req, _id:req, _rev_num_lo:req, _rev_num_hi:req
- func check_erratum_\_cpu\()_\_id
- mov x1, #\_rev_num_lo
- mov x2, #\_rev_num_hi
- b cpu_rev_var_range
- endfunc check_erratum_\_cpu\()_\_id
- .endm
- .macro check_erratum_chosen _cpu:req, _cve:req, _id:req, _chosen:req
- func check_erratum_\_cpu\()_\_id
- .if \_chosen
- mov x0, #ERRATA_APPLIES
- .else
- mov x0, #ERRATA_MISSING
- .endif
- ret
- endfunc check_erratum_\_cpu\()_\_id
- .endm
- /* provide a shorthand for the name format for annoying errata */
- .macro check_erratum_custom_start _cpu:req, _cve:req, _id:req
- func check_erratum_\_cpu\()_\_id
- .endm
- .macro check_erratum_custom_end _cpu:req, _cve:req, _id:req
- endfunc check_erratum_\_cpu\()_\_id
- .endm
- /*******************************************************************************
- * CPU reset function wrapper
- ******************************************************************************/
- /*
- * Wrapper to automatically apply all reset-time errata. Will end with an isb.
- *
- * _cpu:
- * Name of cpu as given to declare_cpu_ops
- *
- * in body:
- * clobber x8 to x14
- * argument x14 - cpu_rev_var
- */
- .macro cpu_reset_func_start _cpu:req
- func \_cpu\()_reset_func
- mov x15, x30
- bl cpu_get_rev_var
- mov x14, x0
- /* short circuit the location to avoid searching the list */
- adrp x12, \_cpu\()_errata_list_start
- add x12, x12, :lo12:\_cpu\()_errata_list_start
- adrp x13, \_cpu\()_errata_list_end
- add x13, x13, :lo12:\_cpu\()_errata_list_end
- errata_begin:
- /* if head catches up with end of list, exit */
- cmp x12, x13
- b.eq errata_end
- ldr x10, [x12, #ERRATUM_WA_FUNC]
- /* TODO(errata ABI): check mitigated and checker function fields
- * for 0 */
- ldrb w11, [x12, #ERRATUM_CHOSEN]
- /* skip if not chosen */
- cbz x11, 1f
- /* skip if runtime erratum */
- cbz x10, 1f
- /* put cpu revision in x0 and call workaround */
- mov x0, x14
- blr x10
- 1:
- add x12, x12, #ERRATUM_ENTRY_SIZE
- b errata_begin
- errata_end:
- .endm
- .macro cpu_reset_func_end _cpu:req
- isb
- ret x15
- endfunc \_cpu\()_reset_func
- .endm
- #endif /* CPU_MACROS_S */
|