The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=0593e4110639d1a84bd7fd785f056998fe8df7e8
commit 0593e4110639d1a84bd7fd785f056998fe8df7e8 Author: Andrew Turner <and...@freebsd.org> AuthorDate: 2025-04-08 10:30:09 +0000 Commit: Andrew Turner <and...@freebsd.org> CommitDate: 2025-04-08 10:48:27 +0000 dev/fdt: Add fdt_foreach_mem_region This is used early in the boot to find physical memory. Previously it needed an array of memory regions to be passed in. We keep finding hardware where this array is too small causing the kernel to smash the stack. Replace with a function that takes a callback that can insert the memory into the physical map directly. Reviewed by: imp Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D49697 --- sys/dev/fdt/fdt_common.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ sys/dev/fdt/fdt_common.h | 3 +++ 2 files changed, 50 insertions(+) diff --git a/sys/dev/fdt/fdt_common.c b/sys/dev/fdt/fdt_common.c index 85d9061759c4..6c505ac2cd7c 100644 --- a/sys/dev/fdt/fdt_common.c +++ b/sys/dev/fdt/fdt_common.c @@ -540,6 +540,53 @@ fdt_get_reserved_mem(struct mem_region *reserved, int *mreserved) return (0); } +int +fdt_foreach_mem_region(fdt_mem_region_cb cb, void *arg) +{ + struct mem_region mr; + pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; + pcell_t *regp; + phandle_t memory; + int addr_cells, size_cells; + int i, reg_len, rv, tuple_size, tuples; + + memory = OF_finddevice("/memory"); + if (memory == -1) + return (ENXIO); + + if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, + &size_cells)) != 0) + return (rv); + + if (addr_cells > 2) + return (ERANGE); + + tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); + reg_len = OF_getproplen(memory, "reg"); + if (reg_len <= 0 || reg_len > sizeof(reg)) + return (ERANGE); + + if (OF_getprop(memory, "reg", reg, reg_len) <= 0) + return (ENXIO); + + tuples = reg_len / tuple_size; + regp = (pcell_t *)® + for (i = 0; i < tuples; i++) { + + rv = fdt_data_to_res(regp, addr_cells, size_cells, + (u_long *)&mr.mr_start, (u_long *)&mr.mr_size); + + if (rv != 0) + return (rv); + + cb(&mr, arg); + + regp += addr_cells + size_cells; + } + + return (0); +} + int fdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint64_t *memsize) { diff --git a/sys/dev/fdt/fdt_common.h b/sys/dev/fdt/fdt_common.h index d19dc5c359a7..f450d976dfe0 100644 --- a/sys/dev/fdt/fdt_common.h +++ b/sys/dev/fdt/fdt_common.h @@ -76,11 +76,14 @@ extern u_char fdt_static_dtb; SYSCTL_DECL(_hw_fdt); +typedef void (*fdt_mem_region_cb)(const struct mem_region *, void *); + int fdt_addrsize_cells(phandle_t, int *, int *); u_long fdt_data_get(void *, int); int fdt_data_to_res(pcell_t *, int, int, u_long *, u_long *); phandle_t fdt_find_compatible(phandle_t, const char *, int); phandle_t fdt_depth_search_compatible(phandle_t, const char *, int); +int fdt_foreach_mem_region(fdt_mem_region_cb, void *); int fdt_get_mem_regions(struct mem_region *, int *, uint64_t *); int fdt_get_reserved_mem(struct mem_region *, int *); int fdt_get_reserved_regions(struct mem_region *, int *);