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