Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 02 Mar 2013 18:18:53 -0700
From:      Ian Lepore <ian@FreeBSD.org>
To:        Tim Kientzle <tim@kientzle.com>
Cc:        freebsd-arm@FreeBSD.org
Subject:   Re: PHYSADDR
Message-ID:  <1362273533.1195.199.camel@revolution.hippie.lan>
In-Reply-To: <AC642AAD-8D8C-429E-AE3B-A34241DA2517@kientzle.com>
References:  <E886046B-1612-425B-902B-72D4B0E93618@freebsd.org> <1362068453.1195.40.camel@revolution.hippie.lan> <674A08B3-6600-4B77-8511-9EF54E4B9B1F@FreeBSD.org> <8FEA3237-8ABF-4564-B672-4B4C0C6EF291@kientzle.com> <1362155632.1195.120.camel@revolution.hippie.lan> <5B622D1B-4EAE-4184-A194-DD14083A48B6@kientzle.com> <1362246634.1195.178.camel@revolution.hippie.lan> <AC642AAD-8D8C-429E-AE3B-A34241DA2517@kientzle.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--=-YTotqcJXRcyvz05kVYP6
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit

On Sat, 2013-03-02 at 10:10 -0800, Tim Kientzle wrote:
> On Mar 2, 2013, at 9:50 AM, Ian Lepore wrote:
> 
> >[...]
> 
> > I'm not sure its safe to assume that (entry-pc & 0xfffff000) is the
> > beginning of the kernel; it's true now but need not be so.  But that's
> > no big deal, we can tweak the linker script to give us the offset of the
> > _start symbol so it'll work no matter what.
> 
> Patches?  ;-)

This turned out to be a bit trickier than I first thought it would be,
but it worked out.

This gets rids of any reference to PHYSADDR and similar constants in the
main path through the code.  I didn't address the "running from flash"
case or anything under #ifdef SMP, yet.  The only constant left is
KERNBASE which is 0xC0000000 for all arm systems.

For now I've got #undef PHYSADDR at the top of the code; this is just
for testing without having to remove it yet from anywhere else.

There are two ldscript changes: define a new ENTRY_OFFSET symbol which
is the offset between the start of the load image and the _start symbol,
and also it puts the physical addresses in the headers, by calculating a
physical value for ENTRY(), and using an AT(expr) for the text segment,
which very conviently just flows to the following segments without
needing to re-specify it on every new segment.

This isn't ready to commit, but it's ready to play with, and to get
comments from folks who know some of the history of this code (Olivier
has been helping me on irc all day answering such questions).

-- Ian


--=-YTotqcJXRcyvz05kVYP6
Content-Description: 
Content-Disposition: inline; filename="locore_physaddr.diff"
Content-Type: text/x-patch; name="locore_physaddr.diff"; charset="us-ascii"
Content-Transfer-Encoding: 7bit

Index: sys/arm/arm/locore.S
===================================================================
--- sys/arm/arm/locore.S	(revision 247421)
+++ sys/arm/arm/locore.S	(working copy)
@@ -41,6 +41,8 @@
 
 __FBSDID("$FreeBSD$");
 
+#undef PHYSADDR
+
 /* What size should this really be ? It is only used by initarm() */
 #define INIT_ARM_STACK_SIZE	(2048 * 4)
 
@@ -52,16 +54,8 @@ __FBSDID("$FreeBSD$");
 	mov	tmp, tmp		/* wait for it to complete */	;\
 	CPWAIT_BRANCH			/* branch to next insn */
 
-/*
- * This is for kvm_mkdb, and should be the address of the beginning
- * of the kernel text segment (not necessarily the same as kernbase).
- */
 	.text
 	.align	0
-.globl kernbase
-.set kernbase,KERNBASE
-.globl physaddr
-.set physaddr,PHYSADDR
 
 /*
  * On entry for FreeBSD boot ABI:
@@ -87,7 +81,7 @@ ASENTRY_NP(_start)
 	orr	r7, r7, #(I32_bit|F32_bit)
 	msr	cpsr_c, r7
 
-#if defined (FLASHADDR) && defined(LOADERRAMADDR)
+#if defined(PHYSADDR) && defined(FLASHADDR) && defined(LOADERRAMADDR)
 	/* Check if we're running from flash. */
 	ldr	r7, =FLASHADDR
 	/*
@@ -123,11 +117,23 @@ Lram_offset:	.word from_ram-_C_LABEL(_start)
 from_ram:
 	nop
 #endif
+
+	/*
+	 * The MMU could be disabled (we're on physical addressing),
+	 * or it could be enabled with VA=PA, or it could be enabled
+	 * with some mystery mapping.  In the latter case, there's no
+	 * easy way to recover the current physical address from the PC.
+	 * We could maybe do a manual tlb walk, but for now we'll just
+	 * require that the physical address be provided at compile time.
+	 * This is all legacy stuff to support redboot long ago.
+	 */
+
 	adr	r7, Lunmapped
+#ifdef PHYSADDR
 	bic     r7, r7, #0xf0000000
 	orr     r7, r7, #PHYSADDR
+#endif
 
-
 disable_mmu:
 	/* Disable MMU for a while */
 	mrc     p15, 0, r2, c1, c0, 0
@@ -142,12 +148,39 @@ disable_mmu:
 	nop
 	mov	pc, r7
 Lunmapped:
+
+#ifdef PHYSADDR
+	ldr	r6, =PHYSADDR		/* If PHYSADDR is provided, use it. */
+#else
+	adr	r0, entry_offset	/* Load the linker-provided offset */
+	ldr	r0, [r0]		/* between _start and the start of */
+	adr	r6, _start		/* the image.  Subtract the offset */
+	sub	r6, r6, r0		/* to get the physical load addr.  */
+#endif
+	adr	r0, kern_physaddr	/* Save it (for debugging mostly). */
+	str	r6, [r0]		/* We'll use the addr to build L1 */
+	mov	r0, #0xff000000		/* section PDEs that map 1MB each; */
+	orr	r0, #0x00f00000		/* mask the load address to round */
+	and	r6, r6, r0		/* to previous 1MB boundary. */
+
 #ifdef STARTUP_PAGETABLE_ADDR
+
 	/* build page table from scratch */
-	ldr	r0, Lstartup_pagetable
 	adr	r4, mmu_init_table
-	b	3f
 
+#define fix_mmu_init(offset)		\
+	ldr	r0, [r4, offset] ;	\
+	orr	r0, r0, r6 ; 		\
+	str	r0, [r4, offset]
+
+	fix_mmu_init(#4)		/* Adjust the va and pa values in */
+	fix_mmu_init(#8)		/* the first two mmu init table */
+	fix_mmu_init(#16)		/* entries to the actual physical */
+	fix_mmu_init(#20)		/* load address calculated above. */
+
+	ldr	r0, Lstartup_pagetable
+	b	3f			/* Go start building the table. */
+
 2:
 	str	r3, [r0, r2]
 	add	r2, r2, #4
@@ -156,11 +189,9 @@ Lunmapped:
 	bhi	2b
 3:
 	ldmia	r4!, {r1,r2,r3}   /* # of sections, VA, PA|attr */
+	mov	r2, r2, LSR #(L1_S_SHIFT-2)
 	cmp	r1, #0
-	adrne	r5, 2b
-	bicne	r5, r5, #0xf0000000
-	orrne	r5, r5, #PHYSADDR
-	movne	pc, r5
+	bne	2b
 
 #if defined(SMP)
 	orr 	r0, r0, #2		/* Set TTB shared memory flag */
@@ -222,15 +253,7 @@ virt_done:
 	b	_C_LABEL(panic)
 	/* NOTREACHED */
 #ifdef STARTUP_PAGETABLE_ADDR
-#define MMU_INIT(va,pa,n_sec,attr) \
-	.word	n_sec					    ; \
-	.word	4*((va)>>L1_S_SHIFT)			    ; \
-	.word	(pa)|(attr)				    ;
 
-Lvirtaddr:
-	.word	KERNVIRTADDR
-Lphysaddr:
-	.word	KERNPHYSADDR
 Lreal_start:
 	.word	_start
 Lend:	
@@ -241,21 +264,47 @@ Lstartup_pagetable:
 Lstartup_pagetable_secondary:
 	.word	temp_pagetable
 #endif
-mmu_init_table:
-	/* fill all table VA==PA */
-	/* map SDRAM VA==PA, WT cacheable */
+
+/* 
+ * mmu_init_table: data used to construct the initial page tables.
+ * 
+ * Note that the first two table entries are magical.  They establish va=pa and
+ * kernva=pa mappings for the first 64 mb starting at the kernel's physical load
+ * address.  The virtual and physical addresses of just the first two entries
+ * are re-written by the code that builds the L1 table, to add in the offset at
+ * which the kernel is physically loaded/running.  Any entries after the first
+ * two are mapped without modification.  This is especially useful for things
+ * like temporarily adding mappings for serial console hardware for debugging.
+ */
 #if !defined(SMP)
-	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
-	/* map VA 0xc0000000..0xc3ffffff to PA */
-	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
+#define VM_ATTR_DEV (L1_TYPE_S|L1_S_AP(AP_KRW))
+#define VM_ATTR_RAM (L1_TYPE_S|L1_S_AP(AP_KRW)|L1_S_C)
 #else
-	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
-	/* map VA 0xc0000000..0xc3ffffff to PA */
-	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
-	MMU_INIT(0x48000000, 0x48000000, 1, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
+#define VM_ATTR_DEV (L1_TYPE_S|L1_S_AP(AP_KRW)|L1_SHARED)
+#define VM_ATTR_RAM (L1_TYPE_S|L1_S_AP(AP_KRW)|L1_SHARED|L1_S_C)
 #endif
+
+#define MMU_INIT(va,pa,n_sec,attr)	  \
+	.word	(n_sec)			; \
+	.word	(va)			; \
+	.word	(pa)|(attr)		;
+
+mmu_init_table:
+	MMU_INIT(0,                   0, 256, VM_ATTR_RAM)
+	MMU_INIT(KERNBASE,            0, 256, VM_ATTR_RAM)
+/*	MMU_INIT(0xFFF00000, 0xFFF00000,   1, VM_ATTR_DEV) example hw entry */
 	.word 0	/* end of table */
-#endif
+
+#endif /* STARTUP_PAGETABLE_ADDR */
+
+	.extern	ENTRY_OFFSET		/* Import this symbol generated by */
+entry_offset:				/* ldscript.arm.  It is the offset */
+	.word	ENTRY_OFFSET		/* of _start in the loaded image. */
+
+	.globl kern_physaddr		/* Export calculated addr, mostly */
+kern_physaddr:				/* for debugging.  There may be */
+	.word	0			/* no reason to keep this. */
+
 .Lstart:
 	.word	_edata
 	.word	_end
Index: sys/conf/ldscript.arm
===================================================================
--- sys/conf/ldscript.arm	(revision 247421)
+++ sys/conf/ldscript.arm	(working copy)
@@ -1,13 +1,17 @@
 /* $FreeBSD$ */
 OUTPUT_ARCH(arm)
-ENTRY(_start)
 
-SEARCH_DIR(/usr/lib);
+PHYSOFFS  = KERNVIRTADDR - KERNPHYSADDR;
+PHYSENTRY = _start - PHYSOFFS;
+
+ENTRY(PHYSENTRY)
+
 SECTIONS
 {
   /* Read-only sections, merged into text segment: */
   . = KERNVIRTADDR + SIZEOF_HEADERS;
-  .text      :
+  ENTRY_OFFSET = _start - KERNVIRTADDR;
+  .text      : AT(ADDR(.text) - PHYSOFFS)  
   {
     *(.text)
     *(.stub)

--=-YTotqcJXRcyvz05kVYP6--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1362273533.1195.199.camel>