Subject: Re: problem with OEA pmap_procwr()
To: Nathan J.Williams <nathanw@wasabisystems.com>
From: Matt Thomas <matt@3am-software.com>
List: port-powerpc
Date: 05/12/2006 17:24:07
On May 12, 2006, at 3:05 PM, Nathan J. Williams wrote:

>
> While working on the GDB import, and prodded a bit by one of the GDB
> developers, I started looking into why the GDB testsuite has many more
> failures on macppc systems than it does on most other systems. The
> general problem is programs continuing when they're supposed to hit a
> breakpoint; this happens more often in the automated testsuite than it
> does manually, but I can reproduce it by hand on my G4 by loading up a
> program ("ls" makes a good test), setting a breakpoint at main(), and
> repeadly entering "run". More often than not, the program will finish
> instead of hitting the breakpoint.
>
> It's not powerpc-general, since a ibm440 evbppc system does much
> better. The symptoms generally point to an icache synchronization
> issue.
>
> Some tracing later, the problem appears to be with process_domem(),
> uvm_io(), and pmap_procwr().
>
> GDB sets a breakpoint with ptrace(PT_WRITE_D) or ptrace(PT_IO), which
> invokes process_domem(). In turn, that does its data move with
> uvm_io(), which maps the relevant section of the target process into
> the kernel's address space, writes to it, and then unmaps
> it. process_domem() then calls pmap_procwr() to do any writeback/cache
> flushing necessary, passing the virtual address and length. The OEA
> pmap looks up that VA in the target process's map, but finds that it's
> not there - gdb is writing to the page before it's been executed by
> the process. So it punts, the icache is left with the old contents,
> and the breakpoint isn't hit.
>
> The problem can be fixed in a pretty clunky way by calling:
>
>    uvm_fault(&vm->vm_map, trunc_page(addr), VM_PROT_EXECUTE);
>
> before pmap_procwr() in process_domem(), thus ensuring that the page
> is present in the target pmap, but this seems like the wrong layer; I
> think pmap_procwr() should do something different to get at the
> underlying physical page even if it's not currently in the PTEGs.

pmap should not be looking in the uvm data structures.  Actually,
there is a better was of fixing this.  This case is taken care in
pmap_protect but doesn't handle pages mapped/modified/unmapped.
This diff should fix that.  Want to give it a shot?

RSA host key for IP address '204.152.190.10' not in list of known hosts.
Index: pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/powerpc/oea/pmap.c,v
retrieving revision 1.36
diff -u -3 -p -r1.36 pmap.c
--- pmap.c      12 May 2006 16:01:05 -0000      1.36
+++ pmap.c      13 May 2006 00:24:24 -0000
@@ -1754,6 +1754,29 @@ pmap_pvo_remove(struct pvo_entry *pvo, i
                 struct vm_page *pg = PHYS_TO_VM_PAGE(ptelo & PTE_RPGN);
                 if (pg != NULL) {
+                       /*
+                        * If this page was changed and it is mapped  
exec,
+                        * invalidate it.
+                        */
+                       if ((ptelo & PTE_CHG) &&
+                           (pmap_attr_get(pg) & PTE_EXEC)) {
+                               struct pvo_head *pvoh =  
vm_page_to_pvoh(pg);
+                               if (LIST_EMPTY(pvoh)) {
+                                       DPRINTFN(EXEC,  
("[pmap_pvo_remove: "
+                                           "%#lx: clear-exec]\n",
+                                           VM_PAGE_TO_PHYS(pg)));
+                                       pmap_attr_clear(pg, PTE_EXEC);
+                                       PMAPCOUNT 
(exec_uncached_clear_modify);
+                               } else {
+                                       DPRINTFN(EXEC,  
("[pmap_pvo_remove: "
+                                           "%#lx: syncicache]\n",
+                                           VM_PAGE_TO_PHYS(pg)));
+                                       pmap_syncicache 
(VM_PAGE_TO_PHYS(pg),
+                                           PAGE_SIZE);
+                                       PMAPCOUNT 
(exec_synced_clear_modify);
+                               }
+                       }
+
                         pmap_attr_save(pg, ptelo & (PTE_REF|PTE_CHG));
                 }
                 PMAPCOUNT(unmappings);