PERFORCE change 160914 for review

Arnar Mar Sig antab at FreeBSD.org
Tue Apr 21 18:41:01 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=160914

Change 160914 by antab at antab_farm on 2009/04/21 18:40:07

	* Rewrite tlb miss handler in assembly and call long path in C for vm_faults
	* Forgot to rearrange one instruction in switch.S that resulted in strange crashes in if_ate

Affected files ...

.. //depot/projects/avr32/src/sys/avr32/avr32/exception.S#9 edit
.. //depot/projects/avr32/src/sys/avr32/avr32/pmap.c#15 edit
.. //depot/projects/avr32/src/sys/avr32/avr32/switch.S#10 edit
.. //depot/projects/avr32/src/sys/avr32/include/tlb.h#5 edit
.. //depot/projects/avr32/src/sys/avr32/include/trap.h#6 edit

Differences ...

==== //depot/projects/avr32/src/sys/avr32/avr32/exception.S#9 (text+ko) ====

@@ -26,11 +26,14 @@
  */
 
 #include <machine/asm.h>
+#include <machine/param.h>
 #include <machine/at32ap700x.h>
 #include <machine/reg.h>
 #include <machine/reg_sys.h>
 #include <machine/reg_intc.h>
 #include <machine/pte.h>
+#include <machine/trap.h>
+#include <machine/tlb.h>
 #include "assym.s"
 
 __FBSDID("$FreeBSD: $");
@@ -130,8 +133,74 @@
 	POP_TRAPFRAME(SUP)
 	rets
 
-/* later this should be done in assembly, but using C for now */
+/*
+ * Page fault short path. If no page is found it calls the long path
+ * r0	PTBR (Page directory)/Page table/Entry pointer
+ * r1	TLBEHI (Failed page address and ASID)
+ * r2	TLBELO (Page entry)
+ * r3	tmp
+ */
 tlb_miss:
+	pushm	r0-r3
+
+	mfsr	r0, AT32_SYS_PTBR			/* Pointer to page directory */
+	mfsr    r1, AT32_SYS_TLBEHI			/* Failed page address */
+
+	bfextu	r3, r1, PD_SHIFT, 10			/* Directory index */
+	ld.w	r0, r0[r3 << 2]				/* Get page table */
+	cp.w	r0, 0					/* No entry */
+	breq	tlb_miss_long
+
+	bfextu	r3, r1, PT_SHIFT, 10			/* Table index */
+	add	r0, r0, r3 << 2				/* Add table index for later use */
+	ld.w	r2, r0					/* Get page entry */
+	cp.w	r2, 0					/* No entry */
+	breq	tlb_miss_long
+
+	/* Mark dirty if write miss */
+	mfsr	r3, AT32_SYS_ECR			/* Get exception number */
+	cp.w	r3, T_TLB_MISS_WRITE			/* Check if Write miss */
+	brne	tlb_miss_1
+	orl	r2, PTE_DIRTY				/* Mark page if so */
+	st.w	r0, r2					/* Save entry */
+
+tlb_miss_1:
+	andl	r2, lo(~PTE_SOFTWARE_MASK)		/* Mask out software */
+	orl	r2, PTE_SIZE_4K				/* All pages are 4k */
+
+	sbr	r1, AT32_SYS_TLBEHI_V			/* Mark entry valid */
+
+/* Entry found, insert it into the TLB */
+tlb_miss_insert:
+	lddpc	r0, tlb_at_ptr				/* Pointer to next tlb */
+	ld.w	r0, r0					/* Next tlb */
+
+	/* Update MMU registers */
+	mfsr	r3, AT32_SYS_MMUCR
+	bfins	r3, r0, AT32_SYS_MMUCR_DRP, AT32_SYS_MMUCR_DRP_SIZE
+	mtsr	AT32_SYS_MMUCR, r3
+	mtsr	AT32_SYS_TLBEHI, r1
+	mtsr	AT32_SYS_TLBELO, r2
+
+	nop						/* Wait for mtsr to exit pipeline */
+	tlbw						/* Write entry */
+	sub pc, -2					/* Flush pipeline */
+
+	sub	r0, -1					/* Increase tlb_at */
+	cp.w	r0, TLB_SIZE				/* At max */
+	moveq	r0, KSTACK_PAGES			/* Reset */
+
+tlb_miss_done:
+	lddpc	r1, tlb_at_ptr				/* Pointer to next tlb */
+	st.w	r1, r0					/* Store next tlb */
+	popm	r0-r3
+	rete
+
+/* No entry found, need to call vm_fault
+ * XXX: This can be done better.
+ */
+tlb_miss_long:
+	popm	r0-r3
 	PUSH_TRAPFRAME(EX)
 	mfsr    r12, AT32_SYS_ECR
 	mfsr    r11, AT32_SYS_TLBEAR
@@ -141,6 +210,13 @@
 	POP_TRAPFRAME(EX)
 	rete
 
+tlb_at_ptr:
+	.long	tlb_at
+
+/*
+ * Steal proc0 stack, maybe we are here because of stack fault
+ * and we are fucked anyway.
+ */
 handle_critical:
 	breakpoint
 	mov	r12, 0

==== //depot/projects/avr32/src/sys/avr32/avr32/pmap.c#15 (text+ko) ====

@@ -1069,87 +1069,77 @@
 	}
 }
 
-/**
- * Called when we need to update the TLB
- * XXX: Split this up, with short path written in assembly and long path
- * here to call vm_fault.
+/*
+ * Called on page fault
  */
-static int tlb_at = KSTACK_PAGES;
+uint32_t tlb_at = KSTACK_PAGES;
 void pmap_tlb_miss(uint32_t ecr, uint32_t tlbear, uint32_t tlbehi, struct trapframe *tf) {
 	pd_entry_t* pd = (pd_entry_t *)sysreg_read(PTBR);
 	struct thread *td = curthread;
 	pt_entry_t *ent;
 	register_t mmucr;
+	struct proc *p = curproc;
+	vm_prot_t ftype;
+	vm_map_t map;
+	vm_offset_t va;
+	int rv = 0;
+	ksiginfo_t ksi;
 
-	ent = (pt_entry_t *)pd[pd_index_from_va(tlbear)];
-	if (ent) {
-		ent += pt_index_from_va(tlbear);
-	}
+	/*
+	 * Enable exceptions before continuing, we are going to
+	 * hit memory that need tlb lookups from here one.
+	 */
+	__asm__ __volatile__ ("csrf %0" : : "i"(AT32_SYS_SR_EM));
+
+	ftype = (ecr == T_TLB_MISS_WRITE) ? VM_PROT_WRITE : VM_PROT_READ;
+	va = trunc_page((vm_offset_t)tlbear);
+
+	if ((vm_offset_t)tlbear < VM_MIN_KERNEL_ADDRESS) {
+		map = &p->p_vmspace->vm_map;
 
-	if (!ent || !*ent) {
 		/*
-		 * Enable exceptions before continuing, we are going to
-		 * hit memory needs tlb lookups from here one.
+		 * Keep swapout from messing with us during this
+		 * critical time.
 		 */
-		__asm__ __volatile__ ("csrf %0" : : "i"(AT32_SYS_SR_EM));
+		PROC_LOCK(p);
+		++p->p_lock;
+		PROC_UNLOCK(p);
 
-		struct proc *p = curproc;
-		vm_prot_t ftype;
-		vm_map_t map;
-		vm_offset_t va;
-		int rv = 0;
-		ksiginfo_t ksi;
+		rv = vm_fault(map, va, ftype,
+			(ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
+						: VM_FAULT_NORMAL);
 
-		ftype = (ecr == T_TLB_MISS_WRITE) ? VM_PROT_WRITE : VM_PROT_READ;
-		va = trunc_page((vm_offset_t)tlbear);
+		PROC_LOCK(p);
+		--p->p_lock;
+		PROC_UNLOCK(p);
+	} else {
+		map = kernel_map;
+		rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
+	}
 
-		if ((vm_offset_t)tlbear < VM_MIN_KERNEL_ADDRESS) {
-			map = &p->p_vmspace->vm_map;
-
-			/*
-			 * Keep swapout from messing with us during this
-			 * critical time.
-			 */
-			PROC_LOCK(p);
-			++p->p_lock;
-			PROC_UNLOCK(p);
-
-			rv = vm_fault(map, va, ftype,
-				(ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
-							: VM_FAULT_NORMAL);
-
-			PROC_LOCK(p);
-			--p->p_lock;
-			PROC_UNLOCK(p);
-		} else {
-			map = kernel_map;
-			rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
+	if (rv != KERN_SUCCESS) {
+		if (!TRAPF_USERMODE(tf)) {
+			panic("Fault in kernel at 0x%x", tlbear);
 		}
 
-		if (rv != KERN_SUCCESS) {
-			if (!TRAPF_USERMODE(tf)) {
-				panic("Fault in kernel at 0x%x", tlbear);
-			}
+		/*
+		 * Generate signal
+		 */
+		td->td_frame->regs.pc = tf->regs.pc;
+		ksiginfo_init_trap(&ksi);
+		ksi.ksi_signo = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+		ksi.ksi_code = ftype;
+		ksi.ksi_addr = (void *)tf->regs.pc;
+		ksi.ksi_trapno = ecr;
+		trapsignal(td, &ksi);
+		avr32_debug("trap out\n");
+		goto out;
+	}
 
-			/*
-			 * Generate signal
-			 */
-			td->td_frame->regs.pc = tf->regs.pc;
-			ksiginfo_init_trap(&ksi);
-			ksi.ksi_signo = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
-			ksi.ksi_code = ftype;
-			ksi.ksi_addr = (void *)tf->regs.pc;
-			ksi.ksi_trapno = ecr;
-			trapsignal(td, &ksi);
+	ent = (pt_entry_t *)pd[pd_index_from_va(tlbear)];
+	KASSERT(ent != NULL, ("Empty pte after success from vm_fault"));
+	ent += pt_index_from_va(tlbear);
 
-			goto out;
-		}
-
-		ent = (pt_entry_t *)pd[pd_index_from_va(tlbear)];
-		KASSERT(ent != NULL, ("Empty pte after success from vm_fault"));
-		ent += pt_index_from_va(tlbear);
-	}
-
 	/* Write miss, mark page as dirty */
 	if (ecr == T_TLB_MISS_WRITE) {
 		*ent |= PTE_DIRTY;
@@ -1160,7 +1150,7 @@
 	mmucr |= tlb_at << bit_shift(SYS, MMUCR, DRP);
 
 	/* Insert into TLB */
-	sysreg_write(TLBEHI, (tlbear & bit_mask(SYS, TLBEHI, VPN)) |
+	sysreg_write(TLBEHI, (tlbehi & bit_mask(SYS, TLBEHI, VPN)) |
 		bit_offset(SYS, TLBEHI, V) |
 		(bit_mask(SYS, TLBEHI, ASID) & tlbehi));
 	sysreg_write(TLBELO, (*ent & ~PTE_SOFTWARE_MASK) | PTE_SIZE_4K);
@@ -1195,5 +1185,6 @@
 	ent += pt_index_from_va(va);
 	KASSERT(ent || *ent, ("Page table entry missing in protection fault"));
 
+	tlb_dump();
 	panic("Finish implementing protection fault");
 }

==== //depot/projects/avr32/src/sys/avr32/avr32/switch.S#10 (text+ko) ====

@@ -82,13 +82,13 @@
 	ld.w	r2, r12[TD_PCB]
 
 	/* Add ASID and V flag to kstack value */
+	ld.w	r10, r12[TD_KSTACK]
 	ld.w	r4, r11[PMAP_ASID]
 	add	r10, r4
 	sbr	r10, AT32_SYS_TLBEHI_V
 	ld.w	r11, r11[PMAP_PD]		/* Point r11 to page directory */
 
 	/* Check if stack is in P3 */
-	ld.w	r10, r12[TD_KSTACK]
 	mov	r9, r10
 	lsr	r9, 29
 	cp	r9, 0x6

==== //depot/projects/avr32/src/sys/avr32/include/tlb.h#5 (text+ko) ====

@@ -29,13 +29,15 @@
 #define _MACHINE_TLB_H_
 
 /* Number of TLB entries, this should be read from config1 */
-#define TLB_SIZE		32	
+#define TLB_SIZE		32
 
+#ifndef LOCORE
 void tlb_dump(void);		/* Dump content of TLB to console */
 void tlb_flush(void);		/* Invalid all TLB entries */
 void tlb_update_entry(pmap_t, vm_offset_t, pt_entry_t);
 void tlb_remove_entry(pmap_t, vm_offset_t);
 void tlb_invalidate_range(pmap_t, vm_offset_t, vm_offset_t);
+#endif
 
 #endif /* !_MACHINE_TLB_H_ */
 

==== //depot/projects/avr32/src/sys/avr32/include/trap.h#6 (text+ko) ====

@@ -29,12 +29,14 @@
 #ifndef _MACHINE_TRAP_H_
 #define _MACHINE_TRAP_H_
 
+#ifndef LOCORE
 #include <machine/frame.h>
 
 void trap_handle_illegal_opcode(uint32_t ecr, struct trapframe *reg);
 void trap_handle_breakpoint(uint32_t ecr, struct trapframe *reg);
 void trap_handle_address_fault(uint32_t ecr, struct trapframe *reg);
 void trapframe_dump(struct trapframe *frame);
+#endif
 
 #define T_BREAKPOINT		0x07
 #define T_TLB_PROT_READ		0x0F
@@ -42,5 +44,4 @@
 #define T_TLB_MISS_READ		0x18
 #define T_TLB_MISS_WRITE	0x1C
 
-
 #endif /* _MACHINE_TRAP_H_ */


More information about the p4-projects mailing list