I was experimenting with a software that generates ARM code at run-time (a JIT compiler). I wanted to run the code also on my Symbian/S60 phone and for this I needed to study the details of Symbian memory management from user-mode perspective as my earlier experiences in writing kernel mode code for didn’t come handy here.
Three things were needed:
- A method of allocating a chunk of virtual memory that is both writable by my threads and can contain executable code
- A method of committing pages of physical memory to the virtual memory chunk for my process
- Some portable way to flush the data and instruction caches for particular data areas when code is modified in this area
I was a little bit worried that Symbian OS Platform Security might limit the applications capabilities in this regards but luckily all this possible using the following APIs:
- RChunk::CreateLocalCode() – Creates a user writable chunk that is marked by the kernel as containing code. The chunk has a maximum size and a committed size.
- UserHeap::ChunkHeap() – Creates a heap in a local chunk that is compatible with the Chunk API.
- User::IMB_Range() – Does the necessary preparations to guarantee correct execution of code in the specified virtual address range. Symbian OS EKA2 kernel can operate in different MMU architectures (ARM4/5) and this API makes handling user mode generated code portable.
All this wasn’t that easy to find since the functionality was fragmented to three classes.
I might post a more complete sample program later.
Cool stuff..
Could you please explain abit on the flushing of the instruction cache?
ie. what is the icache, what does it do etc.
Here’s some code snippets:
Creating a chunk:
if (chunk.CreateLocalCode(initial_size, max_size) != KErrNone)
{
//failed
}
else
{
//see RChunk::Base()
}
Adjusting the chunk:
if(chunk.Adjust(newSize) != KErrNone)
{
//failed
}
And dont forget to close the RChunk :->
chunk.Close()