2004-09-10 00:08:57

by Chris Friesen

[permalink] [raw]
Subject: having problems with remap_page_range() and virt_to_phys()

I'm trying to allocate a page of in-kernel memory and make it accessable to
userspace and to late asm code where we don't have virtual memory enabled.

I'm running code essentially equivalent to the following, where "map_addr" is a
virtual address passed in by userspace, and "vma" is the appropriate one for
that address:


struct page *pg = alloc_page(GFP_KERNEL);
void *virt = page_address(pg);
unsigned long phys = virt_to_phys(virt)
remap_page_range(vma, map_addr, phys, PAGE_SIZE, vma->vm_page_prot)


The problem that I'm having is that after the call to remap_page_range, the
result of

virt_to_phys(map_addr)

is not equal to "phys", and I assume it should be since its supposed to be
pointing to the same physical page as "virt".

Anyone have any ideas? I can't post the exact code right now since the machine
is at work and hung (Oops.) but I could post it tomorrow if that is necessary.

I'm using 2.6.5 for ppc, if it makes any difference.

Thanks,

Chris


2004-09-10 04:04:08

by Peter Chubb

[permalink] [raw]
Subject: Re: having problems with remap_page_range() and virt_to_phys()

>>>>> "Chris" == Chris Friesen <[email protected]> writes:

Chris> I'm trying to allocate a page of in-kernel memory and make it
Chris> accessable to userspace and to late asm code where we don't
Chris> have virtual memory enabled.

Chris> I'm running code essentially equivalent to the following, where
Chris> "map_addr" is a virtual address passed in by userspace, and
Chris> "vma" is the appropriate one for that address:


Chris> struct page *pg = alloc_page(GFP_KERNEL); void *virt =
Chris> page_address(pg); unsigned long phys = virt_to_phys(virt)
Chris> remap_page_range(vma, map_addr, phys, PAGE_SIZE,
Chris> vma->vm_page_prot)


Chris> The problem that I'm having is that after the call to
Chris> remap_page_range, the result of

Chris> virt_to_phys(map_addr)

Did you set the VM_RESERVED bit on the VMA? If you didn't then the remap
page range will allocate a new zero-filled page for you.


--
Dr Peter Chubb http://www.gelato.unsw.edu.au peterc AT gelato.unsw.edu.au
The technical we do immediately, the political takes *forever*

2004-09-10 14:16:13

by Hugh Dickins

[permalink] [raw]
Subject: Re: having problems with remap_page_range() and virt_to_phys()

On Thu, 9 Sep 2004, Chris Friesen wrote:

> I'm trying to allocate a page of in-kernel memory and make it accessable to
> userspace and to late asm code where we don't have virtual memory enabled.
>
> I'm running code essentially equivalent to the following, where "map_addr" is a
> virtual address passed in by userspace, and "vma" is the appropriate one for
> that address:
>
> struct page *pg = alloc_page(GFP_KERNEL);

You will need to SetPageReserved(pg) for remap_page_range to map it.
And no, remembering your earlier pleas, the MM system doesn't clean
up for you, you'll need to ClearPageReserved and free the page when
it's all done with (if ever).

> void *virt = page_address(pg);
> unsigned long phys = virt_to_phys(virt)
> remap_page_range(vma, map_addr, phys, PAGE_SIZE, vma->vm_page_prot)
>
> The problem that I'm having is that after the call to remap_page_range, the
> result of
>
> virt_to_phys(map_addr)

virt_to_phys applies to the kernel virtual address (what you name "virt"
above), it won't work on a user virtual address, that's something else.

> is not equal to "phys", and I assume it should be since its supposed to be
> pointing to the same physical page as "virt".
>
> Anyone have any ideas? I can't post the exact code right now since the machine
> is at work and hung (Oops.) but I could post it tomorrow if that is necessary.
>
> I'm using 2.6.5 for ppc, if it makes any difference.

I'm not a user of remap_page_range (just someone who one day wants
to get rid of PageReserved and incidentally lift that SetPageReserved
restriction), not the best person to advise you. But there are plenty
of examples of using remap_page_range in the kernel source tree, maybe
not all of them quite correct, but I'd have thought you could work out
what you need from those examples.

Hugh

2004-09-10 15:13:42

by Chris Friesen

[permalink] [raw]
Subject: Re: having problems with remap_page_range() and virt_to_phys()

Hugh Dickins wrote:
> On Thu, 9 Sep 2004, Chris Friesen wrote:

> You will need to SetPageReserved(pg) for remap_page_range to map it.
> And no, remembering your earlier pleas, the MM system doesn't clean
> up for you, you'll need to ClearPageReserved and free the page when
> it's all done with (if ever).

Right. I actually did call SetPageReserved(pg), I just forgot to include it in
the code snippet--my test machine is on the other side of the country and I
managed to hose it nicely last night.

> virt_to_phys applies to the kernel virtual address (what you name "virt"
> above), it won't work on a user virtual address, that's something else.

Aha. That may be part of my problem, at least on the verification side.

> But there are plenty
> of examples of using remap_page_range in the kernel source tree, maybe
> not all of them quite correct, but I'd have thought you could work out
> what you need from those examples.

So did I...the code finishes without errors, but the assembly language part
doesn't work properly. (And it does work with another method of getting memory,
but that method breaks as soon as you go highmem...)

Chris

2004-09-10 17:55:42

by Chris Friesen

[permalink] [raw]
Subject: Re: having problems with remap_page_range() and virt_to_phys()

Friesen, Christopher [CAR:VC21:EXCH] wrote:

> So did I...the code finishes without errors, but the assembly language
> part doesn't work properly. (And it does work with another method of
> getting memory, but that method breaks as soon as you go highmem...)

HIGHPTE, I should say.

Chris

2004-09-10 21:01:39

by Chris Friesen

[permalink] [raw]
Subject: problems with remap_page_range() and virt_to_phys() -- solved

Friesen, Christopher [CAR:VC21:EXCH] wrote:


> The problem that I'm having is that after the call to remap_page_range,
> the result of
>
> virt_to_phys(map_addr)
>
> is not equal to "phys", and I assume it should be since its supposed to
> be pointing to the same physical page as "virt".

I seem to have found my problem. There were two things involved:

1) virt_to_phys() doesn't work on user addresses, so you basically have to walk
the page tables. For ppc, iopa() seems to do this although there is a comment
about it not working on pmac (which it seems to).

2) to setup the vma for unmapped areas I was using mmap with MAP_PRIVATE. On
the first write by userspace, the mapping was changed and the user page was no
longer mapped to the desired kernel page. Changing this to MAP_SHARED fixed it.

Chris

2004-09-10 21:39:04

by Chris Friesen

[permalink] [raw]
Subject: Re: having problems with remap_page_range() and virt_to_phys()

Hugh Dickins wrote:

> And no, remembering your earlier pleas, the MM system doesn't clean
> up for you, you'll need to ClearPageReserved and free the page when
> it's all done with (if ever).


Cleanup will be at process death, so I'm adding a routine to be called from
do_exit().

As part of that cleanup, do I need to call do_munmap() on the user virtual
address first, or can I just do

ClearPageReserved(pg);
__free_pages(pg,0);

and then rely on the mm takedown to properly unmap and drop its references?

Basically I'm not sure if I can clear the reservation and free the page while
it's still mapped in the task's memory map.

Chris