1*b5351a43STom Rini // SPDX-License-Identifier: GPL-2.0+
285b46921SHeinrich Schuchardt /*
385b46921SHeinrich Schuchardt  * efi_selftest_unaligned
485b46921SHeinrich Schuchardt  *
585b46921SHeinrich Schuchardt  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
685b46921SHeinrich Schuchardt  *
785b46921SHeinrich Schuchardt  * Test unaligned memory access on ARMv7.
885b46921SHeinrich Schuchardt  */
985b46921SHeinrich Schuchardt 
1085b46921SHeinrich Schuchardt #include <efi_selftest.h>
1185b46921SHeinrich Schuchardt 
1285b46921SHeinrich Schuchardt struct aligned_buffer {
1385b46921SHeinrich Schuchardt 	char a[8] __aligned(8);
1485b46921SHeinrich Schuchardt };
1585b46921SHeinrich Schuchardt 
1685b46921SHeinrich Schuchardt /*
1785b46921SHeinrich Schuchardt  * Return an u32 at a give address.
1885b46921SHeinrich Schuchardt  * If the address is not four byte aligned, an unaligned memory access
1985b46921SHeinrich Schuchardt  * occurs.
2085b46921SHeinrich Schuchardt  *
2185b46921SHeinrich Schuchardt  * @addr:	address to read
2285b46921SHeinrich Schuchardt  * @return:	value at the address
2385b46921SHeinrich Schuchardt  */
deref(u32 * addr)2485b46921SHeinrich Schuchardt static inline u32 deref(u32 *addr)
2585b46921SHeinrich Schuchardt {
2685b46921SHeinrich Schuchardt 	int ret;
2785b46921SHeinrich Schuchardt 
2885b46921SHeinrich Schuchardt 	asm(
2985b46921SHeinrich Schuchardt 		"ldr %[out], [%[in]]\n\t"
3085b46921SHeinrich Schuchardt 		: [out] "=r" (ret)
3185b46921SHeinrich Schuchardt 		: [in] "r" (addr)
3285b46921SHeinrich Schuchardt 	);
3385b46921SHeinrich Schuchardt 	return ret;
3485b46921SHeinrich Schuchardt }
3585b46921SHeinrich Schuchardt 
3685b46921SHeinrich Schuchardt /*
3785b46921SHeinrich Schuchardt  * Execute unit test.
3885b46921SHeinrich Schuchardt  * An unaligned memory access is executed. The result is checked.
3985b46921SHeinrich Schuchardt  *
4085b46921SHeinrich Schuchardt  * @return:	EFI_ST_SUCCESS for success
4185b46921SHeinrich Schuchardt  */
execute(void)4285b46921SHeinrich Schuchardt static int execute(void)
4385b46921SHeinrich Schuchardt {
4485b46921SHeinrich Schuchardt 	struct aligned_buffer buf = {
4585b46921SHeinrich Schuchardt 		{0, 1, 2, 3, 4, 5, 6, 7},
4685b46921SHeinrich Schuchardt 		};
4785b46921SHeinrich Schuchardt 	void *v = &buf;
4885b46921SHeinrich Schuchardt 	u32 r = 0;
4985b46921SHeinrich Schuchardt 
5085b46921SHeinrich Schuchardt 	/* Read an unaligned address */
5185b46921SHeinrich Schuchardt 	r = deref(v + 1);
5285b46921SHeinrich Schuchardt 
5385b46921SHeinrich Schuchardt 	/* UEFI only supports low endian systems */
5485b46921SHeinrich Schuchardt 	if (r != 0x04030201) {
5585b46921SHeinrich Schuchardt 		efi_st_error("Unaligned access failed");
5685b46921SHeinrich Schuchardt 		return EFI_ST_FAILURE;
5785b46921SHeinrich Schuchardt 	}
5885b46921SHeinrich Schuchardt 
5985b46921SHeinrich Schuchardt 	return EFI_ST_SUCCESS;
6085b46921SHeinrich Schuchardt }
6185b46921SHeinrich Schuchardt 
6285b46921SHeinrich Schuchardt EFI_UNIT_TEST(unaligned) = {
6385b46921SHeinrich Schuchardt 	.name = "unaligned memory access",
6485b46921SHeinrich Schuchardt 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
6585b46921SHeinrich Schuchardt 	.execute = execute,
6685b46921SHeinrich Schuchardt };
67