r = fdt32_ld(cells); if (ncells > 1)
r = (r << 32) | fdt32_ld(cells + 1);
return r;
}
/* * Check the start of physical memory * * Traditionally, the start address of physical memory is obtained by masking * the program counter. However, this does require that this address is a * multiple of 128 MiB, precluding booting Linux on platforms where this * requirement is not fulfilled. * Hence validate the calculated address against the memory information in the * DTB, and, if out-of-range, replace it by the real start address. * To preserve backwards compatibility (systems reserving a block of memory * at the start of physical memory, kdump, ...), the traditional method is * used if it yields a valid address, unless the "linux,usable-memory-range" * property is present. * * Return value: start address of physical memory to use
*/
uint32_t fdt_check_mem_start(uint32_t mem_start, constvoid *fdt)
{
uint32_t addr_cells, size_cells, usable_base, base;
uint32_t fdt_mem_start = 0xffffffff; const fdt32_t *usable, *reg, *endp;
uint64_t size, usable_end, end; constchar *type; int offset, len;
if (!fdt) return mem_start;
if (fdt_magic(fdt) != FDT_MAGIC) return mem_start;
/* There may be multiple cells on LPAE platforms */
addr_cells = get_cells(fdt, "#address-cells");
size_cells = get_cells(fdt, "#size-cells"); if (addr_cells > 2 || size_cells > 2) return mem_start;
/* * Usable memory in case of a crash dump kernel * This property describes a limitation: memory within this range is * only valid when also described through another mechanism
*/
usable = get_prop(fdt, "/chosen", "linux,usable-memory-range",
(addr_cells + size_cells) * sizeof(fdt32_t)); if (usable) {
size = get_val(usable + addr_cells, size_cells); if (!size) return mem_start;
if (addr_cells > 1 && fdt32_ld(usable)) { /* Outside 32-bit address space */ return mem_start;
}
/* Walk all memory nodes and regions */ for (offset = fdt_next_node(fdt, -1, NULL); offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
type = fdt_getprop(fdt, offset, "device_type", NULL); if (!type || strcmp(type, "memory")) continue;
reg = fdt_getprop(fdt, offset, "linux,usable-memory", &len); if (!reg)
reg = fdt_getprop(fdt, offset, "reg", &len); if (!reg) continue;
base = fdt32_ld(reg + addr_cells - 1);
end = base + size; if (usable) { /* * Clip to usable range, which takes precedence * over mem_start
*/ if (base < usable_base)
base = usable_base;
if (end > usable_end)
end = usable_end;
if (end <= base) continue;
} elseif (mem_start >= base && mem_start < end) { /* Calculated address is valid, use it */ return mem_start;
}
if (base < fdt_mem_start)
fdt_mem_start = base;
}
}
if (fdt_mem_start == 0xffffffff) { /* No usable memory found, falling back to default */ return mem_start;
}
/* * The calculated address is not usable, or was overridden by the * "linux,usable-memory-range" property. * Use the lowest usable physical memory address from the DTB instead, * and make sure this is a multiple of 2 MiB for phys/virt patching.
*/ return round_up(fdt_mem_start, SZ_2M);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.