blob: 6a80ad7eb7bac1f771a189e1080e753b32c5051b [file]
/*
* Copyright (c) 2022, Google Inc. All rights reserved
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <asm.h>
#include <arch/asm_macros.h>
#include <err.h>
#include "btitest.h"
.section .text
/* Fault handler to return where BTI calls fail.
* On return from the caught Branch Target exception, PSTATE.BTYPE will still
* be set according to the last branch taken. Therefore we need to land on a
* BTI jc to be compatible with all callers - and avoid another immediate
* Branch Target exception.
*/
.Lbtitest_callee_fault:
bti jc
mov x0, #ERR_FAULT
ret
/**
* int btitest_bl(void) - Use bl to call each of the test functions
*
* This calls each of the test functions using bl and a relative offset,
* which should always be allowed. The functions are expected to all return 0.
*
* Returns The first non-zero return code, or 0 if all functions pass.
*/
FUNCTION(btitest_bl)
push lr, xzr
bl btitest_callee_nop
cbnz x0, .Lerror
bl btitest_callee_bti
cbnz x0, .Lerror
bl btitest_callee_bti_c
cbnz x0, .Lerror
bl btitest_callee_bti_j
cbnz x0, .Lerror
bl btitest_callee_bti_jc
cbnz x0, .Lerror
bl btitest_callee_paciasp
cbnz x0, .Lerror
bl btitest_callee_pacibsp
.Lerror:
pop lr, xzr
ret
/**
* int btitest_blr(int) - Use blr to call the passed function
*
* Returns The called function's return value
*/
FUNCTION(btitest_blr)
push lr, xzr
bl get_callee
blr x0
pop lr, xzr
ret
/**
* int btitest_br(int) - Use br to call the passed function via the x0 register
*
* Returns The called function's return value
*/
FUNCTION(btitest_br)
push lr, xzr
bl get_callee
pop lr, xzr
br x0
/**
* int btitest_br_x16(int) - Use br to call the passed function via the x16
* register
*
* Returns The called function's return value
*/
FUNCTION(btitest_br_x16)
push lr, xzr
bl get_callee
pop lr, xzr
mov x16, x0
br x16
/**
* int btitest_br_x17(int) - Use br to call the passed function via the x17
* register
*
* Returns The called function's return value
*/
FUNCTION(btitest_br_x17)
push lr, xzr
bl get_callee
pop lr, xzr
mov x17, x0
br x17
/**
* int btitest_callee_nop(void) - Function with nop instruction
*
* Returns ERR_FAULT if the BTI check fails.
* Return 0 if the BTI check passes.
*/
LOCAL_FUNCTION(btitest_callee_nop)
set_fault_handler .Lbtitest_callee_fault
nop
mov x0, #0
ret
/**
* int btitest_callee_bti(void) - Function with bti instruction
*
* Returns ERR_FAULT if the BTI check fails.
* Return 0 if the BTI check passes.
*/
LOCAL_FUNCTION(btitest_callee_bti)
set_fault_handler .Lbtitest_callee_fault
bti
mov x0, #0
ret
/**
* int btitest_callee_bti_c(void) - Function with bti c instruction
*
* Returns ERR_FAULT if the BTI check fails.
* Return 0 if the BTI check passes.
*/
LOCAL_FUNCTION(btitest_callee_bti_c)
set_fault_handler .Lbtitest_callee_fault
bti c
mov x0, #0
ret
/**
* int btitest_callee_bti_j(void) - Function with bti j instruction
*
* Returns ERR_FAULT if the BTI check fails.
* Return 0 if the BTI check passes.
*/
LOCAL_FUNCTION(btitest_callee_bti_j)
set_fault_handler .Lbtitest_callee_fault
bti j
mov x0, #0
ret
/**
* int btitest_callee_bti_jc(void) - Function with bti jc instruction
*
* Returns ERR_FAULT if the BTI check fails.
* Return 0 if the BTI check passes.
*/
LOCAL_FUNCTION(btitest_callee_bti_jc)
set_fault_handler .Lbtitest_callee_fault
bti jc
mov x0, #0
ret
/**
* int btitest_callee_paciasp(void) - Function with paciasp instruction
*
* Returns ERR_FAULT if the BTI check fails.
* Return 0 if the BTI check passes.
*/
LOCAL_FUNCTION(btitest_callee_paciasp)
set_fault_handler .Lbtitest_callee_fault
paciasp
mov x0, #0
autiasp
ret
/**
* int btitest_callee_pacibsp(void) - Function with pacibsp instruction
*
* Returns ERR_FAULT if the BTI check fails.
* Return 0 if the BTI check passes.
*/
LOCAL_FUNCTION(btitest_callee_pacibsp)
set_fault_handler .Lbtitest_callee_fault
pacibsp
mov x0, #0
autibsp
ret
/**
* int btitest_callee_error(void) - Error function which always fails
*
* This is valid as any jump target.
*
* Returns ERR_INVALID_ARGS unconditionally.
*/
LOCAL_FUNCTION(btitest_callee_error)
bti jc
mov x0, #ERR_INVALID_ARGS
ret
/**
* get_callee(int) - Get the address of the callee function.
*
* Converts the passed function index into the function address.
* This is done here to avoid using the C compiler to get function addresses -
* the compiler may insert veneers or indirection under some situations (e.g.
* for CFI) and break the specific landing pad instructions needed to test BTI.
*
* Return 0 if the index is not recognised, otherwise the function address.
*/
LOCAL_FUNCTION(get_callee)
cmp w0, #BTITEST_CALLEE_NOP
bne .Ltry_bti
adr x0, btitest_callee_nop
ret
.Ltry_bti:
cmp w0, #BTITEST_CALLEE_BTI
bne .Ltry_bti_c
adr x0, btitest_callee_bti
ret
.Ltry_bti_c:
cmp w0, #BTITEST_CALLEE_BTI_C
bne .Ltry_bti_j
adr x0, btitest_callee_bti_c
ret
.Ltry_bti_j:
cmp w0, #BTITEST_CALLEE_BTI_J
bne .Ltry_bti_jc
adr x0, btitest_callee_bti_j
ret
.Ltry_bti_jc:
cmp w0, #BTITEST_CALLEE_BTI_JC
bne .Ltry_paciasp
adr x0, btitest_callee_bti_jc
ret
.Ltry_paciasp:
cmp w0, #BTITEST_CALLEE_PACIASP
bne .Ltry_pacibsp
adr x0, btitest_callee_paciasp
ret
.Ltry_pacibsp:
cmp w0, #BTITEST_CALLEE_PACIBSP
bne .Lunknown
adr x0, btitest_callee_pacibsp
ret
.Lunknown:
/* Return error function which unconditionally fails any test */
adr x0, btitest_callee_error
ret