Mapping an executable page

Thomas De Schampheleire patrickdepinguin+linuxppc at gmail.com
Tue Jun 14 18:56:31 EST 2011


Hi,

On Sun, May 29, 2011 at 4:53 PM, Tabi Timur-B04825 <B04825 at freescale.com> wrote:
> On Fri, May 27, 2011 at 8:25 AM, Thomas De Schampheleire
> <patrickdepinguin+linuxppc at gmail.com> wrote:
>
>> Although I realize that what I need to achieve is unconventional, what
>> is the correct way of mapping a certain address range into memory, and
>> be able to execute from it?
>
> Have you tried looking at the actual TLB entry for this page to see if
> it's correct?  Also, you might need to do some kind of instruction
> cache flushing before you jump to that page.

Sorry to have delayed this so long.
I had to do quite some experimentation to get it finally working. Here
are my findings:
* to map a page as executable, the following does indeed work:
void __iomem *vaddr = __ioremap(map_start, map_size, (_PAGE_BASE |
_PAGE_KERNEL_RWX));

* However, if you jump to an address in that page, you'll have to make
sure that the entire code that executes is mapped (make map_size large
enough).

* When that range spanned multiple pages, I faced the issue of only
one page being actually mapped in the TLBs. My assumption is that the
call to __ioremap not necessarily updates the TLBs, but mainly some
kernel-internal tables. The actual TLB mapping presumably happens when
a data exception occurs.
Unfortunately, since I left the Linux kernel and jumped to other
(boot) code that reassigns the exception vectors, the kernel-internal
tables are not used anymore, and the exception handler cannot update
the TLBs correctly.

* Therefore, to make sure that the mapping I intended with __ioremap()
is actually reflected in the TLB tables, I added dummy reads of each
page in the TLB, prior to jumping to the boot code, as follows:
                /* make sure memory is read, once every 4Kbyte is enough */
                for (p = vaddr; p < vaddr + map_size; p += 0x1000) {
                        unsigned long dummy = *(volatile unsigned long *)p;
                        (void)dummy;
                }

* After these changes (make sure all code is mapped + make sure to
read all pages so that the TLBs are updated), my scenario works fine.

Best regards,
Thomas


More information about the Linuxppc-dev mailing list