Index: sys/powerpc/ofw/ofw_machdep.c =================================================================== --- sys/powerpc/ofw/ofw_machdep.c +++ sys/powerpc/ofw/ofw_machdep.c @@ -225,41 +225,19 @@ #ifdef FDT static int -excise_fdt_reserved(struct mem_region *avail, int asz) +excise_reserved_regions(struct mem_region *avail, int asz, + struct mem_region *exclude, int esz) { - struct { - uint64_t address; - uint64_t size; - } fdtmap[32]; - ssize_t fdtmapsize; - phandle_t chosen; int i, j, k; - chosen = OF_finddevice("/chosen"); - fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); - - for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { - fdtmap[j].address = be64toh(fdtmap[j].address) & ~PAGE_MASK; - fdtmap[j].size = round_page(be64toh(fdtmap[j].size)); - } - - KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap), - ("Exceeded number of FDT reservations")); - /* Add a virtual entry for the FDT itself */ - if (fdt != NULL) { - fdtmap[j].address = (vm_offset_t)fdt & ~PAGE_MASK; - fdtmap[j].size = round_page(fdt_totalsize(fdt)); - fdtmapsize += sizeof(fdtmap[0]); - } - for (i = 0; i < asz; i++) { - for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { + for (j = 0; j < esz; j++) { /* * Case 1: Exclusion region encloses complete * available entry. Drop it and move on. */ - if (fdtmap[j].address <= avail[i].mr_start && - fdtmap[j].address + fdtmap[j].size >= + if (exclude[j].mr_start <= avail[i].mr_start && + exclude[j].mr_start + exclude[j].mr_size >= avail[i].mr_start + avail[i].mr_size) { for (k = i+1; k < asz; k++) avail[k-1] = avail[k]; @@ -274,20 +252,20 @@ * a new available entry with the region after * the excluded region, if any. */ - if (fdtmap[j].address >= avail[i].mr_start && - fdtmap[j].address < avail[i].mr_start + + if (exclude[j].mr_start >= avail[i].mr_start && + exclude[j].mr_start < avail[i].mr_start + avail[i].mr_size) { - if (fdtmap[j].address + fdtmap[j].size < + if (exclude[j].mr_start + exclude[j].mr_size < avail[i].mr_start + avail[i].mr_size) { avail[asz].mr_start = - fdtmap[j].address + fdtmap[j].size; + exclude[j].mr_start + exclude[j].mr_size; avail[asz].mr_size = avail[i].mr_start + avail[i].mr_size - avail[asz].mr_start; asz++; } - avail[i].mr_size = fdtmap[j].address - + avail[i].mr_size = exclude[j].mr_start - avail[i].mr_start; } @@ -297,13 +275,13 @@ * The case of a contained exclusion zone has already * been caught in case 2. */ - if (fdtmap[j].address + fdtmap[j].size >= - avail[i].mr_start && fdtmap[j].address + - fdtmap[j].size < avail[i].mr_start + + if (exclude[j].mr_start + exclude[j].mr_size >= + avail[i].mr_start && exclude[j].mr_start + + exclude[j].mr_size < avail[i].mr_start + avail[i].mr_size) { avail[i].mr_size += avail[i].mr_start; avail[i].mr_start = - fdtmap[j].address + fdtmap[j].size; + exclude[j].mr_start + exclude[j].mr_size; avail[i].mr_size -= avail[i].mr_start; } } @@ -311,6 +289,62 @@ return (asz); } + +static int +excise_initrd_region(struct mem_region *avail, int asz) +{ + phandle_t chosen; + uint64_t start, end; + ssize_t size; + struct mem_region initrdmap[1]; + + chosen = OF_finddevice("/chosen"); + size = OF_getprop(chosen, "linux,initrd-start", &start, sizeof(start)); + if (size <= 0) + return (asz); + + size = OF_getprop(chosen, "linux,initrd-end", &end, sizeof(end)); + if (size <= 0) + return (asz); + + initrdmap[0].mr_start = start; + initrdmap[0].mr_size = end - start; + + asz = excise_reserved_regions(avail, asz, initrdmap, 1); + + return (asz); +} + +static int +excise_fdt_reserved(struct mem_region *avail, int asz) +{ + struct mem_region fdtmap[32]; + ssize_t fdtmapsize; + phandle_t chosen; + int j, fdtentries; + + chosen = OF_finddevice("/chosen"); + fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); + + for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { + fdtmap[j].mr_start = be64toh(fdtmap[j].mr_start) & ~PAGE_MASK; + fdtmap[j].mr_size = round_page(be64toh(fdtmap[j].mr_size)); + } + + KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap), + ("Exceeded number of FDT reservations")); + /* Add a virtual entry for the FDT itself */ + if (fdt != NULL) { + fdtmap[j].mr_start = (vm_offset_t)fdt & ~PAGE_MASK; + fdtmap[j].mr_size = round_page(fdt_totalsize(fdt)); + fdtmapsize += sizeof(fdtmap[0]); + } + + fdtentries = fdtmapsize/sizeof(fdtmap[0]); + asz = excise_reserved_regions(avail, asz, fdtmap, fdtentries); + + return (asz); +} #endif /* @@ -364,6 +398,13 @@ phandle = OF_finddevice("/chosen"); if (OF_hasprop(phandle, "fdtmemreserv")) asz = excise_fdt_reserved(availp, asz); + + /* If the kernel is being loaded through kexec, initrd region is listed + * in /chosen but the region is not marked as reserved, so, we might exclude + * it here. + */ + if (OF_hasprop(phandle, "linux,initrd-start")) + asz = excise_initrd_region(availp, asz); #endif *memsz = msz;