Date: Fri, 1 Jun 2018 12:43:13 +0000 (UTC) From: Breno Leitao <leitao@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r334485 - head/sys/powerpc/ofw Message-ID: <201806011243.w51ChDNl096928@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: leitao Date: Fri Jun 1 12:43:13 2018 New Revision: 334485 URL: https://svnweb.freebsd.org/changeset/base/334485 Log: powerpc64: Avoid overwriting initrd area Currently kexec loads an initrd file into the main memory but does not mark that region as reserved, thus the area is not protected. If any initrd/md file is loaded from kexec/petitboot, the region might become corarupted/overwritten since FreeBSD does not know the region is 'reserved'. This patch simply adds the initrd area as a reserved memory region. Approved by: jhibbits Differential Revision: https://reviews.freebsd.org/D15610 Modified: head/sys/powerpc/ofw/ofw_machdep.c Modified: head/sys/powerpc/ofw/ofw_machdep.c ============================================================================== --- head/sys/powerpc/ofw/ofw_machdep.c Fri Jun 1 12:09:07 2018 (r334484) +++ head/sys/powerpc/ofw/ofw_machdep.c Fri Jun 1 12:43:13 2018 (r334485) @@ -225,41 +225,19 @@ parse_ofw_memory(phandle_t node, const char *prop, str #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 @@ excise_fdt_reserved(struct mem_region *avail, int asz) * 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 @@ excise_fdt_reserved(struct mem_region *avail, int asz) * 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 @@ excise_fdt_reserved(struct mem_region *avail, int asz) 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 @@ ofw_mem_regions(struct mem_region *memp, int *memsz, 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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806011243.w51ChDNl096928>