mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
The C standard qualifies misaligned pointers as undefined behavior. This means it is fundamentally impossible to define a conformant C API for unaligned access that is expressed in terms of types with a minimum alignment greater than 1 byte. Undefined behavior means that the compiler is free to generate code that assumes that only the defined behavior occurs. This means that a C implementation of ReadUnaligned64() might be emitted using a 64-bit load operation that does not tolerate misalignment, depending on the CPU architecture. So the only correct way to define such an API is in terms of types such as VOID* that have no implied alignment. Then, given that compilers today are perfectly capable of generating the right code, given accurate annotations, let's rely on those in the generic implementation. This will ensure that the correct access sequences are used, depending on the CPU architecture, and on the compiler flags (e.g., AArch64 uses -mstrict-align in XIP code as it may execute with the MMU disabled). Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
225 lines
5.1 KiB
C
225 lines
5.1 KiB
C
/** @file
|
|
Unaligned access functions of BaseLib.
|
|
|
|
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "BaseLibInternals.h"
|
|
|
|
#pragma pack(1)
|
|
typedef union {
|
|
UINT16 Val16;
|
|
UINT32 Val32;
|
|
UINT64 Val64;
|
|
} MISALIGNED;
|
|
#pragma pack()
|
|
|
|
STATIC_ASSERT (ALIGNOF (MISALIGNED) == 1, "Alignment error");
|
|
|
|
/**
|
|
Reads a 16-bit value from memory that may be unaligned.
|
|
|
|
This function returns the 16-bit value pointed to by Buffer. The function
|
|
guarantees that the read operation does not produce an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 16-bit value that may be unaligned.
|
|
|
|
@return The 16-bit value read from Buffer.
|
|
|
|
**/
|
|
UINT16
|
|
EFIAPI
|
|
ReadUnaligned16 (
|
|
IN CONST VOID *Buffer
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
return ((CONST MISALIGNED *)Buffer)->Val16;
|
|
}
|
|
|
|
/**
|
|
Writes a 16-bit value to memory that may be unaligned.
|
|
|
|
This function writes the 16-bit value specified by Value to Buffer. Value is
|
|
returned. The function guarantees that the write operation does not produce
|
|
an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 16-bit value that may be unaligned.
|
|
@param Value 16-bit value to write to Buffer.
|
|
|
|
@return The 16-bit value to write to Buffer.
|
|
|
|
**/
|
|
UINT16
|
|
EFIAPI
|
|
WriteUnaligned16 (
|
|
OUT VOID *Buffer,
|
|
IN UINT16 Value
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
return ((MISALIGNED *)Buffer)->Val16 = Value;
|
|
}
|
|
|
|
/**
|
|
Reads a 24-bit value from memory that may be unaligned.
|
|
|
|
This function returns the 24-bit value pointed to by Buffer. The function
|
|
guarantees that the read operation does not produce an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 24-bit value that may be unaligned.
|
|
|
|
@return The 24-bit value read from Buffer.
|
|
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
ReadUnaligned24 (
|
|
IN CONST VOID *Buffer
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
return ((UINT32)((UINT8 *)Buffer)[2] << 16) | ReadUnaligned16 (Buffer);
|
|
}
|
|
|
|
/**
|
|
Writes a 24-bit value to memory that may be unaligned.
|
|
|
|
This function writes the 24-bit value specified by Value to Buffer. Value is
|
|
returned. The function guarantees that the write operation does not produce
|
|
an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 24-bit value that may be unaligned.
|
|
@param Value 24-bit value to write to Buffer.
|
|
|
|
@return The 24-bit value to write to Buffer.
|
|
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
WriteUnaligned24 (
|
|
OUT VOID *Buffer,
|
|
IN UINT32 Value
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
WriteUnaligned16 (Buffer, (UINT16)Value);
|
|
((UINT8 *)Buffer)[2] = (UINT8)(Value >> 16);
|
|
return Value & 0xffffff;
|
|
}
|
|
|
|
/**
|
|
Reads a 32-bit value from memory that may be unaligned.
|
|
|
|
This function returns the 32-bit value pointed to by Buffer. The function
|
|
guarantees that the read operation does not produce an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 32-bit value that may be unaligned.
|
|
|
|
@return The 32-bit value read from Buffer.
|
|
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
ReadUnaligned32 (
|
|
IN CONST VOID *Buffer
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
return ((CONST MISALIGNED *)Buffer)->Val32;
|
|
}
|
|
|
|
/**
|
|
Writes a 32-bit value to memory that may be unaligned.
|
|
|
|
This function writes the 32-bit value specified by Value to Buffer. Value is
|
|
returned. The function guarantees that the write operation does not produce
|
|
an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 32-bit value that may be unaligned.
|
|
@param Value The 32-bit value to write to Buffer.
|
|
|
|
@return The 32-bit value to write to Buffer.
|
|
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
WriteUnaligned32 (
|
|
OUT VOID *Buffer,
|
|
IN UINT32 Value
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
return ((MISALIGNED *)Buffer)->Val32 = Value;
|
|
}
|
|
|
|
/**
|
|
Reads a 64-bit value from memory that may be unaligned.
|
|
|
|
This function returns the 64-bit value pointed to by Buffer. The function
|
|
guarantees that the read operation does not produce an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 64-bit value that may be unaligned.
|
|
|
|
@return The 64-bit value read from Buffer.
|
|
|
|
**/
|
|
UINT64
|
|
EFIAPI
|
|
ReadUnaligned64 (
|
|
IN CONST VOID *Buffer
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
return ((CONST MISALIGNED *)Buffer)->Val64;
|
|
}
|
|
|
|
/**
|
|
Writes a 64-bit value to memory that may be unaligned.
|
|
|
|
This function writes the 64-bit value specified by Value to Buffer. Value is
|
|
returned. The function guarantees that the write operation does not produce
|
|
an alignment fault.
|
|
|
|
If the Buffer is NULL, then ASSERT().
|
|
|
|
@param Buffer A pointer to a 64-bit value that may be unaligned.
|
|
@param Value The 64-bit value to write to Buffer.
|
|
|
|
@return The 64-bit value to write to Buffer.
|
|
|
|
**/
|
|
UINT64
|
|
EFIAPI
|
|
WriteUnaligned64 (
|
|
OUT VOID *Buffer,
|
|
IN UINT64 Value
|
|
)
|
|
{
|
|
ASSERT (Buffer != NULL);
|
|
|
|
return ((MISALIGNED *)Buffer)->Val64 = Value;
|
|
}
|