Skip site navigation (1)Skip section navigation (2)
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>