1*85b46921SHeinrich Schuchardt /*
2*85b46921SHeinrich Schuchardt  * efi_selftest_unaligned
3*85b46921SHeinrich Schuchardt  *
4*85b46921SHeinrich Schuchardt  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
5*85b46921SHeinrich Schuchardt  *
6*85b46921SHeinrich Schuchardt  * SPDX-License-Identifier:     GPL-2.0+
7*85b46921SHeinrich Schuchardt  *
8*85b46921SHeinrich Schuchardt  * Test unaligned memory access on ARMv7.
9*85b46921SHeinrich Schuchardt  */
10*85b46921SHeinrich Schuchardt 
11*85b46921SHeinrich Schuchardt #include <efi_selftest.h>
12*85b46921SHeinrich Schuchardt 
13*85b46921SHeinrich Schuchardt struct aligned_buffer {
14*85b46921SHeinrich Schuchardt 	char a[8] __aligned(8);
15*85b46921SHeinrich Schuchardt };
16*85b46921SHeinrich Schuchardt 
17*85b46921SHeinrich Schuchardt /*
18*85b46921SHeinrich Schuchardt  * Return an u32 at a give address.
19*85b46921SHeinrich Schuchardt  * If the address is not four byte aligned, an unaligned memory access
20*85b46921SHeinrich Schuchardt  * occurs.
21*85b46921SHeinrich Schuchardt  *
22*85b46921SHeinrich Schuchardt  * @addr:	address to read
23*85b46921SHeinrich Schuchardt  * @return:	value at the address
24*85b46921SHeinrich Schuchardt  */
25*85b46921SHeinrich Schuchardt static inline u32 deref(u32 *addr)
26*85b46921SHeinrich Schuchardt {
27*85b46921SHeinrich Schuchardt 	int ret;
28*85b46921SHeinrich Schuchardt 
29*85b46921SHeinrich Schuchardt 	asm(
30*85b46921SHeinrich Schuchardt 		"ldr %[out], [%[in]]\n\t"
31*85b46921SHeinrich Schuchardt 		: [out] "=r" (ret)
32*85b46921SHeinrich Schuchardt 		: [in] "r" (addr)
33*85b46921SHeinrich Schuchardt 	);
34*85b46921SHeinrich Schuchardt 	return ret;
35*85b46921SHeinrich Schuchardt }
36*85b46921SHeinrich Schuchardt 
37*85b46921SHeinrich Schuchardt /*
38*85b46921SHeinrich Schuchardt  * Execute unit test.
39*85b46921SHeinrich Schuchardt  * An unaligned memory access is executed. The result is checked.
40*85b46921SHeinrich Schuchardt  *
41*85b46921SHeinrich Schuchardt  * @return:	EFI_ST_SUCCESS for success
42*85b46921SHeinrich Schuchardt  */
43*85b46921SHeinrich Schuchardt static int execute(void)
44*85b46921SHeinrich Schuchardt {
45*85b46921SHeinrich Schuchardt 	struct aligned_buffer buf = {
46*85b46921SHeinrich Schuchardt 		{0, 1, 2, 3, 4, 5, 6, 7},
47*85b46921SHeinrich Schuchardt 		};
48*85b46921SHeinrich Schuchardt 	void *v = &buf;
49*85b46921SHeinrich Schuchardt 	u32 r = 0;
50*85b46921SHeinrich Schuchardt 
51*85b46921SHeinrich Schuchardt 	/* Read an unaligned address */
52*85b46921SHeinrich Schuchardt 	r = deref(v + 1);
53*85b46921SHeinrich Schuchardt 
54*85b46921SHeinrich Schuchardt 	/* UEFI only supports low endian systems */
55*85b46921SHeinrich Schuchardt 	if (r != 0x04030201) {
56*85b46921SHeinrich Schuchardt 		efi_st_error("Unaligned access failed");
57*85b46921SHeinrich Schuchardt 		return EFI_ST_FAILURE;
58*85b46921SHeinrich Schuchardt 	}
59*85b46921SHeinrich Schuchardt 
60*85b46921SHeinrich Schuchardt 	return EFI_ST_SUCCESS;
61*85b46921SHeinrich Schuchardt }
62*85b46921SHeinrich Schuchardt 
63*85b46921SHeinrich Schuchardt EFI_UNIT_TEST(unaligned) = {
64*85b46921SHeinrich Schuchardt 	.name = "unaligned memory access",
65*85b46921SHeinrich Schuchardt 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
66*85b46921SHeinrich Schuchardt 	.execute = execute,
67*85b46921SHeinrich Schuchardt };
68