Patch to align virt and phys spaces on i386

Glenn Brown <[email protected]> Wed, 08 Mar 2006 10:19:42 -0800
Newsgroups gmane.network.etherboot.devel
Message-ID <[email protected]>
The attached patch increases i386 virt_offset alignment to 4kB, so
the bottom 12 bits of corresponding virt and bus addrs will be identical.

This change facilitates porting drivers to Etherboot, as the vast 
majority of driver execution environments have this virt/bus alignment 
relationship, and non-Etherboot drivers often assume bus addresses are 
aligned if the corresponding virtual addrs are aligned.

PCI Express requires DMAs not cross 4kB boundaries, and this large 
alignment is required by my forthcoming myri10ge.c 10Gb PCI Express 
driver, which is a minimal port of our Linux driver.  Other Linux driver 
ports in the future would also surely benefit from this patch.

I have successully tested this approach with our myri10ge.c driver on 
all 8 PCI express motherboards I have available to me, representing the 
following hardware:
     CPUs: AMD Opteron and Intel EM64T
     Chipsets: Serverworks, Invidia, VIA, Intel, SiS
     BIOSes: AMI, Award, IBM, Phoenix AwardBIOS, and Phoenix TrustedCore.

The "HAVE_VIRT_OFFSET" lines of the patch are not strictly necessary, 
but are there for clarity and to avoid changing non-i386 behaviour,
since I have no way to test non-i386.

Eager for feeback,
--Glenn
relocate.patch (text/plain, 2.6 KB)
Index: src/arch/i386/include/io.h
===================================================================
RCS file: /repository/etherboot/src/arch/i386/include/io.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -a -u -a -u -r1.1.1.1 -r1.2
--- src/arch/i386/include/io.h	27 Nov 2005 20:48:44 -0000	1.1.1.1
+++ src/arch/i386/include/io.h	7 Mar 2006 23:30:28 -0000	1.2
@@ -4,6 +4,7 @@
 
 /* Amount of relocation etherboot is experiencing */
 extern unsigned long virt_offset;
+#define HAVE_VIRT_OFFSET 1
 
 /* Don't require identity mapped physical memory,
  * osloader.c is the only valid user at the moment.
Index: src/bin/.keepme
===================================================================
RCS file: src/bin/.keepme
diff -N src/bin/.keepme
Index: src/core/relocate.c
===================================================================
RCS file: /repository/etherboot/src/core/relocate.c,v
retrieving revision 1.1
retrieving revision 1.4
diff -a -u -a -u -r1.1 -r1.4
--- src/core/relocate.c	27 Nov 2005 21:13:50 -0000	1.1
+++ src/core/relocate.c	7 Mar 2006 23:31:47 -0000	1.4
@@ -15,6 +15,14 @@
  * 
  */
 
+/* Align any virt_offset on this power-of-two boundary, so
+ * virt_to_phys() et al. will not alter the less significant bits.
+ * This should match the maximum DMA alignment that might be required
+ * by on the system, so drivers can assume that aligned virtual
+ * addresses will be similarly aligned in bus address space.
+ */
+#define VIRT_ALIGN 4096 /* PCI Express forbids DMA's across 4KB boundaries */
+
 void relocate(void)
 {
 	unsigned long addr, eaddr, size;
@@ -30,7 +38,11 @@
 	addr = virt_to_phys(_text);
 	eaddr = virt_to_phys(_end);
 	size = (eaddr - addr + 0xf) & ~0xf;
-
+#ifdef HAVE_VIRT_OFFSET
+	/* Allocate an oversized block so we can realign within it. */
+	size += VIRT_ALIGN;
+#endif /* HAVE_VIRT_OFFSET */
+ 
 	/* If the current etherboot is beyond MAX_ADDR pretend it is
 	 * at the lowest possible address.
 	 */
@@ -85,9 +97,26 @@
 		}
 		if (eaddr < r_end - size) {
 			addr = r_end - size;
-			eaddr = r_end;
+			eaddr = addr + (_end - _text);
 		}
 	}
+
+#ifdef HAVE_VIRT_OFFSET
+	/* Adjust the relocation to align virt_offset.
+	 *
+	 * relocate_to(addr) sets virt_offset=addr-_text, so without
+	 * any adjustment, the misalignment would be
+	 * (addr-_text)&(VIRT_ALIGN-1).  We force this misalignment to
+	 * be zero here.
+	 */
+	{
+		unsigned long delta = (((unsigned long) _text - addr)
+				       & (VIRT_ALIGN-1));
+		addr += delta;
+		eaddr += delta;
+	}
+#endif /* HAVE_VIRT_OFFSET */
+	
 	if (addr != virt_to_phys(_text)) {
 		unsigned long old_addr = virt_to_phys(_text);
 		printf("Relocating _text from: [%lx,%lx) to [%lx,%lx)\n",