[linux-sh:03344] Re: [linuxsh-dev] Re: Howto convert from process virtual (linear address) to physical address?

Stuart MENEFY <[email protected]> Fri, 8 Oct 2004 19:25:58 +0100
Newsgroups gmane.linux.ports.sh.general,gmane.linux.ports.sh.devel
Organization STMicroelectronics (Bristol)
Message-ID <[email protected]>
On Fri, 8 Oct 2004 20:34:22 +0300 Paul Mundt <[email protected]> wrote:

> On Fri, Oct 08, 2004 at 05:40:32PM +0100, Alex Bennee wrote:
> > Now I'm probably just lost because I haven't got my head fully wrapped
> > around the multi-level page tables but this is what I've got:
> > 
> >     do {
> > 	pgd_t *pgd;
> > 	pmd_t *pmd;
> > 	pte_t *ptep, pte;
> > 	struct page *the_page;
> > 	unsigned long phys_addr;
> > 	
> >  	get_user(addr, start_addr);
> > 	start_addr++;
> > 
> >         pgd = pgd_offset(tsk->mm, addr);
> >         if (pgd_none(*pgd) || pgd_bad(*pgd))
> > 	    goto out;
> >  
> >         pmd = pmd_offset(pgd, addr);
> >         if (pmd_none(*pmd) || pmd_bad(*pmd))
> > 	    goto out;
> >  
> >         ptep = pte_offset(pmd, addr);
> >         if (!ptep)
> > 	    goto out;
> >  
> >         pte = *ptep;
> > 
> > 	the_page = pte_page(pte);
> > 	phys_addr = page_to_phys(the_page)+(addr&PAGE_MASK);
> 
> This looks problematic.
> 
> What about:
> 
> 	phys_addr = pte_val(*ptep) & PTE_PHYS_MASK;

You still need to OR in the page offset, so:

	phys_addr = (pte_val(*ptep) & PTE_PHYS_MASK) | (addr&(PAGE_SIZE-1));

would be my version.

> > Any idea where I'm going wrong? A pointer to code that actually needs to
> > convert from user-space linear address to actual physical address would
> > be cool if anyone can point me to one.
> > 
> The closest you will probably get is copy/clear_user_page(), but that
> probably won't help you much.

I'd suggest __do_page_fault() but you're missing the last step, converting
a PTE to an address with that.

Either way, I think your code is roughly right, the problem is that the
HUDI doesn't allow you to look at physical memory directly. You're still
seeing memory through the CPU, so you need to use a full 32 bit address.

So you could have done:

(gdb) x/i 0x00413dc8

directly, which might work, if the ASID is still correct, and the TLB
entry was still present.

The problem comes when there is no TLB entry mapping the virtual address,
in this case the code running in the ASE mode has no way to fix up the TLB
miss (if it even knows about it), so returns garbage. So you need to use
the page table walk your doing, but then use a P1 or P2 address, in this
case:

(gdb) x/i 0x89e57dc8

should have done the right thing.

Stuart

-- 
Stuart Menefy                                        [email protected]
STMicroelectronics Ltd                      ST Intranet: linux.bri.st.com
Bristol, UK                        Rest of the World: www.superhlinux.com
signature.asc (application/pgp-signature, 189 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQFBZtu261BlSKQGbXkRAtJSAJ9DE0WAnUdj7U/WhPlkWlQpxn/1AwCgiSa7
85XDIkvy9hwmUKwORFhbSVQ=
=dzBI
-----END PGP SIGNATURE-----