Port-powerpc archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: problem with OEA pmap_procwr()




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);



Home | Main Index | Thread Index | Old Index