Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,71 @@ jobs:
exit 1
fi

- name: Check bootrom SRAM window fit
run: |
# The bootrom copies this image into SRAM at 0x04010500 and SRAM
# ends at 0x04014000, so everything ahead of the compressed payload
# must fit in 0x3B00 (15104) bytes. Overrun it and the chip cannot
# be recovered over UART at all -- it stops answering mid-upload.
# See OpenIPC/firmware#2299. The window is not a whole number of
# 1 KB blocks and the payload must start on a 1 KB boundary, so the
# number to reach is the window rounded down: 0x3800 (14336).
#
# mini-boot.lds ASSERTs the same number at link time; this re-checks
# the artifact we actually ship, because mini-boot.bin is assembled
# from the ELF by dd after linking.
#
# The boundary is found by locating the exact image_data.lzma this
# build produced and requiring it to appear once. Scanning for a
# compression header instead -- which is what recovery tools have to
# do, having only the image -- can match a coincidental byte
# sequence in the prelude and validate a boundary that is not the
# payload's, i.e. pass while the real prelude is oversized.
#
# The window is not met yet (#5), so the hard gate here is a ratchet
# against the current size -- the shortfall is reported every build
# so it stays visible until it reaches zero.
python3 - "u-boot-${{ matrix.board }}-universal.bin" \
$(find arch/arm/cpu -name image_data.lzma) <<'EOF'
import sys
WINDOW = 0x3B00 # what the bootrom can actually load into SRAM
TARGET = WINDOW & ~0x3FF # ...rounded down, because of the ALIGN below
CEILING = 0x4400 # what this build achieves; ratchet, lower only
art, payloads = sys.argv[1], sys.argv[2:]
if len(payloads) != 1:
sys.exit("expected exactly one image_data.lzma under arch/arm/cpu,"
" found %d%s" % (len(payloads),
": " + " ".join(payloads) if payloads else ""))
d = open(art, 'rb').read()
p = open(payloads[0], 'rb').read()
off = d.find(p)
if off < 0:
sys.exit("%s does not contain %s -- the shipped image is not the "
"one this build linked" % (art, payloads[0]))
if d.find(p, off + 1) != -1:
sys.exit("%s occurs more than once in %s -- the prelude boundary "
"is ambiguous" % (payloads[0], art))
print("- %s: prelude [%d/%d bytes]" % (art, off, TARGET))
if off % 1024:
sys.exit("-- payload not 1 KB aligned (recovery tools round the "
"boundary down to 1 KB and would clip code)")
if off > CEILING:
sys.exit("-- grew past the %d-byte ratchet by %d bytes; this "
"number may only go down" % (CEILING, off - CEILING))
if off > TARGET:
# Warning, not a failure: this image still boots from flash, and
# failing here would stop both boards shipping a working
# bootloader over a recovery-path-only defect. Annotated so the
# gap is visible in the checks UI, not just in the log.
print("::warning title=mini-boot exceeds bootrom SRAM window::"
"%s prelude is %d bytes over the %d-byte target; this SoC "
"cannot be recovered over UART with its own u-boot. "
"Tracking: OpenIPC/u-boot-hi3516cv200#5"
% (art, off - TARGET, TARGET))
else:
print("-- margin: %d bytes" % (TARGET - off))
EOF

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
Expand Down
5 changes: 3 additions & 2 deletions arch/arm/cpu/hi3518ev200/compressed/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ OBJCOPY := $(CROSS_COMPILE)objcopy
BOOT := mini-boot
TEXTBASE := 0x80700000

CFLAGS := -g -O2 -fno-strict-aliasing -fno-common -ffixed-r8 \
CFLAGS := -g -Os -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-common -ffixed-r8 \
-D__KERNEL__ -DTEXT_BASE=$(TEXTBASE) \
-I$(TOPDIR)/include \
-I$(TOPDIR)/drivers/ddr \
Expand Down Expand Up @@ -90,7 +90,7 @@ $(BOOT).tmp: $(BOOT).elf
$(OBJCOPY) --gap-fill=0xff -O binary $< $@

$(BOOT).elf: image_data.lzma $(SRC) $(START) $(COBJS)
$(LD) -Bstatic -T mini-boot.lds -Ttext $(TEXTBASE) $(START) \
$(LD) -Bstatic --gc-sections -T mini-boot.lds -Ttext $(TEXTBASE) $(START) \
$(COBJS) -Map $(BOOT).map -o $@

.PHONY: regfile
Expand All @@ -112,6 +112,7 @@ start.o: start.S
image_data.lzma: $(BINIMAGE)
lzma -fkzc -7 $< > $@


%.o: %.c
$(CC) $(CFLAGS) -Wall -Wstrict-prototypes \
-fno-stack-protector -o $@ $< -c
Expand Down
47 changes: 38 additions & 9 deletions arch/arm/cpu/hi3518ev200/compressed/mini-boot.lds
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,57 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)

/* The bootrom copies this image into SRAM at 0x04010500, and SRAM ends at
* 0x04014000. Everything ahead of the compressed payload -- the vector
* table, the 4 KB reg_info block and all mini-boot code -- therefore has to
* fit in 0x3B00 bytes. Overrunning it writes over the bootrom's own stack:
* the chip stops answering mid-transfer and the board cannot be recovered
* over UART at all. See OpenIPC/firmware#2299. */
MINI_BOOT_SRAM_WINDOW = 0x3B00;

/* The window is not a multiple of 1 KB, and the payload has to start on a
* 1 KB boundary (see the ALIGN below), so the largest prelude that is both
* loadable and not clipped is the window rounded down: 0x3800 (14336). That
* is the number to aim at, not 0x3B00. */
MINI_BOOT_SRAM_TARGET = 0x3800;

/* What this build actually achieves today. It is NOT yet inside the target
* above -- see OpenIPC/u-boot-hi3516cv200#5 -- so the assert below ratchets
* against the current size instead: it may only ever be lowered, never
* raised, so the gap cannot silently grow again while it is being closed. */
MINI_BOOT_SIZE_CEILING = 0x4400;

SECTIONS
{
. = 0x00000000;

. = ALIGN(4);
.text :
{
start.o (.text)
lowlevel_init_svb.o (.text)
ddr_training_impl.o (.text)
ddr_training_ctl.o (.text)
ddr_training_boot.o (.text)
ddr_training_custom.o (.text)
*(.text)
start.o (.text .text.*)
lowlevel_init_svb.o (.text .text.*)
ddr_training_impl.o (.text .text.*)
ddr_training_ctl.o (.text .text.*)
ddr_training_boot.o (.text .text.*)
ddr_training_custom.o (.text .text.*)
*(.text .text.*)
}
__text_end = .;

. = ALIGN(4);
/* Start the payload on a 1 KB boundary. Recovery tools find the end of
* the SRAM-resident program by scanning for the compressed header and
* rounding DOWN to 1 KB; without this padding that rounding clips the
* tail of the last function. */
. = ALIGN(1024);
__image_start = .;
.image : { *(.image) }

. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

. = ALIGN(4);
.data : { *(.data) }
.data : { *(.data .data.*) }

. = ALIGN(4);
.got : { *(.got) }
Expand All @@ -36,3 +62,6 @@ SECTIONS
.bss : { *(.bss) }
_end = .;
}

ASSERT(__image_start - ADDR(.text) <= MINI_BOOT_SIZE_CEILING,
"mini-boot grew past MINI_BOOT_SIZE_CEILING. The target is MINI_BOOT_SRAM_TARGET (0x3800) -- anything above that cannot be recovered over UART at all -- so this must go down, not up. See OpenIPC/u-boot-hi3516cv200#5.")
Loading