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