ARM passes -mstrict-align (-mno-unaligned-access on ARMv7) to everything,
because when the MMU is off any unaligned access there faults. The
compiler then has to assemble every wide unaligned load out of single
bytes: one ldr becomes eight ldrb and seven orr/lsl.

This is especially painful for decompressors which refill their buffer
in 64-bit words. On a Rockchip RK3576 SPL, zstd unpacks a 30MiB Falcon
mode Linux kernel in 1947ms built this way and 596ms without the flag,
and the SPL gets 2.3KiB smaller by cutting down on the byte-wise loads and
ORs. gzip, whose inflate walks its input a byte at a time anyway, gains
6%.

Add ASSUME_UNALIGNED_ACCESS_OK for a platform to state that the MMU is on
by the time it unpacks an image, and let the decompression libraries drop
the flag when it is set. The arch exports the flag it added rather than
lib/ naming it, so this stays correct for anything else which adds one.

No functional change anywhere until the symbol is selected.

Signed-off-by: Alexey Charkov <[email protected]>
---
 arch/Kconfig                 | 35 +++++++++++++++++++++++++++++++++++
 arch/arm/cpu/armv7/config.mk |  3 +++
 arch/arm/cpu/armv8/config.mk |  3 +++
 lib/Makefile                 |  3 +++
 lib/lzma/Makefile            |  8 ++++++++
 lib/lzo/Makefile             |  8 ++++++++
 lib/zlib/Makefile            |  8 ++++++++
 lib/zstd/Makefile            |  8 ++++++++
 8 files changed, 76 insertions(+)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8d63afeb138e..606b9d79ecd8 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -27,6 +27,41 @@ config SUPPORT_LITTLE_ENDIAN
        bool
        default y if !SUPPORT_BIG_ENDIAN
 
+config ASSUME_UNALIGNED_ACCESS_OK
+       bool
+       help
+         Assume that an unaligned access cannot fault by the time U-Boot
+         proper unpacks an image, and build the decompression libraries
+         without the architecture's strict-alignment flag on that basis.
+
+         Architectures whose unaligned accesses fault while the MMU is off
+         pass such a flag to everything, which makes the compiler assemble
+         each wide unaligned load out of single bytes. That is both slower
+         and larger, and a decompressor refilling its bit buffer in machine
+         words can spend up to four times as long for it.
+
+         The assumption holds only once the MMU is on, which on most
+         platforms has not happened by the time an image is unpacked, and
+         nothing checks it. Select it from code which enables the MMU
+         first, under the same condition that code tests, so that the two
+         cannot drift apart. It has no prompt because there is no safe way
+         to answer it by hand.
+
+         The flag is only dropped from the decompression libraries. Every
+         other part of U-Boot keeps it, including all of the code which runs
+         before the MMU comes up.
+
+config SPL_ASSUME_UNALIGNED_ACCESS_OK
+       bool
+       depends on SPL
+       help
+         The same assumption for SPL, which on most platforms runs with the
+         MMU off from start to finish and must therefore leave the flag
+         alone. See ASSUME_UNALIGNED_ACCESS_OK.
+
+         There is deliberately no TPL or VPL variant: those phases run before
+         DRAM is up, so the flag always stays.
+
 config SYS_CACHE_SHIFT_4
        bool
 
diff --git a/arch/arm/cpu/armv7/config.mk b/arch/arm/cpu/armv7/config.mk
index 68036d6fbdaf..a1d1fb40d78e 100644
--- a/arch/arm/cpu/armv7/config.mk
+++ b/arch/arm/cpu/armv7/config.mk
@@ -9,3 +9,6 @@
 # of our decision.
 PF_NO_UNALIGNED := $(call cc-option, -mno-unaligned-access,)
 PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
+# Code which only runs with the MMU on may drop this again; see
+# CONFIG_ASSUME_UNALIGNED_ACCESS_OK.
+export PF_NO_UNALIGNED
diff --git a/arch/arm/cpu/armv8/config.mk b/arch/arm/cpu/armv8/config.mk
index 4d74b2a533e0..a27d3e3aa8a1 100644
--- a/arch/arm/cpu/armv8/config.mk
+++ b/arch/arm/cpu/armv8/config.mk
@@ -6,6 +6,9 @@ PLATFORM_RELFLAGS += $(call cc-option,-mbranch-protection=none)
 
 PF_NO_UNALIGNED := $(call cc-option, -mstrict-align)
 PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
+# Code which only runs with the MMU on may drop this again; see
+# CONFIG_ASSUME_UNALIGNED_ACCESS_OK.
+export PF_NO_UNALIGNED
 
 EFI_LDS := elf_aarch64_efi.lds
 EFI_CRT0 := crt0_aarch64_efi.o
diff --git a/lib/Makefile b/lib/Makefile
index b7272c6f0cba..dd93d41df5d7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -93,6 +93,9 @@ obj-$(CONFIG_$(PHASE_)GZIP) += gunzip.o
 obj-$(CONFIG_$(PHASE_)LZO) += lzo/
 obj-$(CONFIG_$(PHASE_)LZMA) += lzma/
 obj-$(CONFIG_$(PHASE_)LZ4) += lz4_wrapper.o
+ifdef CONFIG_$(PHASE_)ASSUME_UNALIGNED_ACCESS_OK
+CFLAGS_REMOVE_lz4_wrapper.o += $(PF_NO_UNALIGNED)
+endif
 
 obj-$(CONFIG_$(PHASE_)LIB_RATIONAL) += rational.o
 
diff --git a/lib/lzma/Makefile b/lib/lzma/Makefile
index 09380074b3df..1a85b5210386 100644
--- a/lib/lzma/Makefile
+++ b/lib/lzma/Makefile
@@ -10,3 +10,11 @@ ccflags-y += -DZ7_LZMA_PROB32
 ccflags-$(CONFIG_$(PHASE_)LZMA_SIZE_OPTIMIZATION) += -DZ7_LZMA_SIZE_OPT
 
 obj-y += LzmaDec.o LzmaTools.o
+
+# These only run once an image is being unpacked, which on some platforms is
+# late enough that unaligned accesses are safe. Where the platform says so,
+# let the compiler use them: assembling a 64-bit read out of bytes is both
+# slower and larger.
+ifdef CONFIG_$(PHASE_)ASSUME_UNALIGNED_ACCESS_OK
+ccflags-remove-y += $(PF_NO_UNALIGNED)
+endif
diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile
index 45612a83dabc..66b02ede0f19 100644
--- a/lib/lzo/Makefile
+++ b/lib/lzo/Makefile
@@ -4,3 +4,11 @@
 # Stefan Roese, DENX Software Engineering, [email protected].
 
 obj-y += lzo1x_decompress.o
+
+# These only run once an image is being unpacked, which on some platforms is
+# late enough that unaligned accesses are safe. Where the platform says so,
+# let the compiler use them: assembling a 64-bit read out of bytes is both
+# slower and larger.
+ifdef CONFIG_$(PHASE_)ASSUME_UNALIGNED_ACCESS_OK
+ccflags-remove-y += $(PF_NO_UNALIGNED)
+endif
diff --git a/lib/zlib/Makefile b/lib/zlib/Makefile
index 4a3e985a9494..9ad1c73b3e6c 100644
--- a/lib/zlib/Makefile
+++ b/lib/zlib/Makefile
@@ -4,3 +4,11 @@
 # Wolfgang Denk, DENX Software Engineering, [email protected].
 
 obj-y += zlib.o
+
+# These only run once an image is being unpacked, which on some platforms is
+# late enough that unaligned accesses are safe. Where the platform says so,
+# let the compiler use them: assembling a 64-bit read out of bytes is both
+# slower and larger.
+ifdef CONFIG_$(PHASE_)ASSUME_UNALIGNED_ACCESS_OK
+ccflags-remove-y += $(PF_NO_UNALIGNED)
+endif
diff --git a/lib/zstd/Makefile b/lib/zstd/Makefile
index c9a7dfe405b4..76b8a992d7b1 100644
--- a/lib/zstd/Makefile
+++ b/lib/zstd/Makefile
@@ -35,3 +35,11 @@ zstd_common-y := \
                common/error_private.o \
                common/fse_decompress.o \
                common/zstd_common.o \
+
+# These only run once an image is being unpacked, which on some platforms is
+# late enough that unaligned accesses are safe. Where the platform says so,
+# let the compiler use them: assembling a 64-bit read out of bytes is both
+# slower and larger.
+ifdef CONFIG_$(PHASE_)ASSUME_UNALIGNED_ACCESS_OK
+ccflags-remove-y += $(PF_NO_UNALIGNED)
+endif

-- 
2.55.0

Reply via email to