Reputation: 51
I am writing a Linux kernel module that needs to map a specific physical address to a specific virtual one, and I just can't find a way to do it.
Upvotes: 1
Views: 1191
Reputation: 51
OK, This is my current solution. To map phys_addr
to virt_addr
I use this code:
page = pfn_to_page(virt_addr >> PAGE_SHIFT);
pte = get_locked_pte(&init_mm, phys_addr, &ptl);
set_pte_at(&init_mm, phys_addr, pte, mk_pte(page, VM_READ | VM_WRITE | VM_EXEC));
spin_unlock(ptl);
flush_tlb_all();
Some explenations: I use the pfn_to_page
func to get the page struct corresponding to my virt_addr
. I get the page table entry (pte
) with the get_locked_pte
func which needs the physical address corresponding to the wanted pte
and an uninitalized spinlock (ptl
). Then, I actually map the page using set_pte_at
func and the mk_pte
macro, unlock the spinlock and flush the tlb cache.
This solution seems to work pretty well, though it does not survive a context switch.
Upvotes: 3
Reputation: 1826
Could you tell us the kernel version and CPU architecture/type you are using? Generally speaking, if the specific virtual address you want to mapping to does not overlap with kernel virtual address(such as 0xC0000000), and also if the physical address which your device is using does not overlap with system memory physical address range, you can using the low-level functions(if there is not, you can using assemble language to set up MMU TLB entries directly during kernel booting up) to set up MMU TLB entries to map the specific address to a specific virtual one during kernel booting up. I can provide one example based on 2.6.10 kernel version and Freescale PowerPC CPU, there is a function io_block_mapping to do the thing you want.
Upvotes: 0