Skip to content

Commit b60bd31

Browse files
dgarskedanielinux
authored andcommitted
Peer review feedback (thanks Daniele)
1 parent 14f6e4a commit b60bd31

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

hal/zynq.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,14 @@ int hal_fpga_load(uint32_t flags, uintptr_t addr, size_t size)
17311731
uint32_t ret_payload[PM_ARGS_CNT];
17321732
uint32_t pmflags;
17331733

1734+
/* size is passed to the PMU as a 32-bit word below. On AArch64 size_t is
1735+
* 64-bit, so reject anything that would truncate. A real bitstream is at
1736+
* most a few tens of MB. */
1737+
if (size == 0 || size > 0xFFFFFFFFUL) {
1738+
wolfBoot_printf("PM_FPGA_LOAD: bad bitstream size\n");
1739+
return -1;
1740+
}
1741+
17341742
/* PM_FPGA_LOAD takes the bitstream size in BYTES (the PMU firmware
17351743
* divides by the word length internally for the CSU DMA). This
17361744
* matches stock Xilinx U-Boot (drivers/fpga/zynqmppl.c passes

hal/zynq7000.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ static void z7_dcache_clean_range(uintptr_t start, uint32_t len)
899899
int hal_fpga_load(uint32_t flags, uintptr_t addr, size_t size)
900900
{
901901
uint32_t sts;
902-
uint32_t words = (uint32_t)((size + 3U) / 4U);
902+
uint32_t words;
903903
uint64_t t0;
904904

905905
if (flags == HAL_FPGA_PARTIAL) {
@@ -911,14 +911,31 @@ int hal_fpga_load(uint32_t flags, uintptr_t addr, size_t size)
911911
if (addr > 0xFFFFFFFFU || size == 0) {
912912
return -1;
913913
}
914+
#if defined(SIZE_MAX) && SIZE_MAX > 0xFFFFFFFFU
915+
/* words and the DMA length register are 32-bit; reject a size that would
916+
* truncate. Compiled out where size_t is already 32-bit. */
917+
if (size > 0xFFFFFFFFU) {
918+
wolfBoot_printf("Z7 FPGA: bitstream size too large\n");
919+
return -1;
920+
}
921+
#endif
914922
/* The DevC DMA descriptor encodes the "last" flag in the source
915923
* address LSB, so the bitstream buffer must be word-aligned. */
916924
if ((addr & 0x3U) != 0U) {
917925
wolfBoot_printf("Z7 FPGA: bitstream addr not word-aligned\n");
918926
return -1;
919927
}
920928

921-
/* 1. Unlock DevC and select PCAP (not ICAP). */
929+
/* Round byte size up to whole words without overflowing size + 3. */
930+
words = (uint32_t)(size / 4U);
931+
if ((size & 3U) != 0U) {
932+
words++;
933+
}
934+
935+
/* 1. Unlock DevC and select PCAP (not ICAP). PCAP_MODE=1 enables the
936+
* PCAP interface; PCAP_PR=1 selects PCAP (0 would select ICAP) per
937+
* UG585 devcfg.CTRL bit 27. This matches Xilinx FSBL pcap.c, which
938+
* sets both bits for full-bitstream programming. */
922939
Z7_DEVC_UNLOCK = Z7_DEVC_UNLOCK_KEY;
923940
Z7_DEVC_CTRL |= (Z7_DEVC_CTRL_PCAP_MODE | Z7_DEVC_CTRL_PCAP_PR);
924941
/* Disable internal PCAP loopback. */
@@ -954,7 +971,18 @@ int hal_fpga_load(uint32_t flags, uintptr_t addr, size_t size)
954971
* bitstreams are word streams, so this normally equals size.) */
955972
z7_dcache_clean_range(addr, words * 4U);
956973

957-
/* 6. Program the DMA: src = DDR bitstream (LSB=1 marks last descriptor),
974+
/* 6. Wait for room in the DevC DMA command queue, then program the DMA.
975+
* Writing a descriptor while the queue is full silently drops it,
976+
* leaving step 7 to spin to the timeout. */
977+
t0 = hal_get_timer_us();
978+
while (Z7_DEVC_STATUS & Z7_DEVC_STATUS_DMA_CMD_FULL) {
979+
if (hal_get_timer_us() - t0 > Z7_FPGA_TIMEOUT_US) {
980+
wolfBoot_printf("Z7 FPGA: timeout waiting DMA queue space\n");
981+
return -1;
982+
}
983+
}
984+
985+
/* src = DDR bitstream (LSB=1 marks last descriptor),
958986
* dst = PCAP sentinel. Lengths are in 32-bit words. */
959987
Z7_DEVC_DMA_SRC = ((uint32_t)addr) | Z7_DEVC_DMA_LAST;
960988
Z7_DEVC_DMA_DST = Z7_DEVC_DMA_DEST_PCAP;

0 commit comments

Comments
 (0)