0% found this document useful (0 votes)
123 views26 pages

Dokumen - Tips Linux Mmap Ioremap Introduction

The document discusses ioremap and mmap functions in Linux for mapping physical addresses to virtual addresses. Ioremap is used when physical addresses are outside of the virtual address space, allowing hardware registers to be accessed. Mmap provides a way to map files or devices into memory and share mappings between processes using flags like MAP_SHARED. It improves performance over read/write system calls by eliminating data copying between kernel and user spaces.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
123 views26 pages

Dokumen - Tips Linux Mmap Ioremap Introduction

The document discusses ioremap and mmap functions in Linux for mapping physical addresses to virtual addresses. Ioremap is used when physical addresses are outside of the virtual address space, allowing hardware registers to be accessed. Mmap provides a way to map files or devices into memory and share mappings between processes using flags like MAP_SHARED. It improves performance over read/write system calls by eliminating data copying between kernel and user spaces.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 26

ioremap & mmap in Linux

Taichien Chang

1
Outline
How to access Physical Address?
Why ioremap? & ioremap func.
 Flow of I/O Memory Map Access
 Why MMAP?
MMAP Syscall. & MMAP func.
MMAP flags : MAP_SHARED, MAP_PRIVATE ,
MAP_LOCKED.
Flow of implement of mmap
remap_pfn_range func.
The implement of mmap file operation

2
How to access Physical Address ?
1. Drivers use virtual address. “Virtual Memory NOT Physical RAM"
2. H/W use physical address(Registers,RAM)
3. Virtual memory doesn’t store anything, it simply maps a
program’s address space onto the underlying physical memory.
In Direct Mapping Area :
Virtual Address Physical Address
4G

MMU RAM

Kernel Space
0xd0200000

0xc0000000 3G phys_to_virt() or __pa()

User Space 0x200000


I/O Mem
0x10200000

3
Address Translation func.

MIPS architectures.

PAGE_OFFSET= 0XC000000 (for x86)

PAGE_OFFSET= 0x80000000 (for MIPS Cached Address)


PAGE_OFFSET= 0xA0000000 (for MIPS Uncached Address)

4
Why ioremap ?
1. When physical memory or I/O Address is larger than virtual address
space size.(0xffffffff)
phys_to_virt(0x40200000)= 0x00300000 ????
2. How to access these extra physical addresses?
“Using I/O Memory Mapping"

Virtual Address Physical Address


0xffffffff 4G
Reserved for MMIO
x86 128MB MMU RAM
0xf8044000

Kernel Space I/O Mem


ioremap() 0x40200000

0xc0000000 3G

User Space 0x200000

3. 5Use __pa(high_memory)? 0x377fe000 ≒ 896MB


ioremap func.
#include <asm/io.h>
__u32 __iomem virt_addr = ioremap(unsigned long phys_addr, unsigned long size);
__u32 __iomem virt_addr = ioremap_nocache(unsigned long phys_addr, unsigned long size);
void iounmap(void * virt_addr );

You should not directly access addresses returned by ioremap as if they


were pointer to virtual memory address. Why?
 We have these functions to access H/W register
“Guarantee read/write ordering"

readb(addr)
readw(addr)
readl(addr)
writeb(val,addr)
writew(val,addr)
writel(val,addr)
memcpy_fromio(buffer,addr, len);
memcpy_toio(addr,buffer,len);
memset_io(addr,val,len);

6
Flow of I/O Memory Map Access
#include <asm/ioport.h>
Using
request_mem_region(unsigned long start, unsigned long len, char *name);
to reserve [start , start+len] region into “iomem_resource” & avoid another driver to use them.
 All I/O memory allocations are listed in /proc/iomem.

request_mem_region(phy_addr,len,”NAME”)

Driver Open
virt_addr = ioremap(phy_addr,len)

readb/readw/readl (virt_addr)
writeb/writew/writel (val,virt_addr)

iounmap(virt_addr)

Driver Release
release_mem_region(phy_addr,len)
7
Memory Mapping between kernel & User space

Q:How can AP directly access to physical address ? (RAM or Registers)


A:Kernel provide a system call - “mmap” 1.Reserved Memory
2.Dynamic Memory
對 kernel virtual address 調用 virt_to_phys 也是沒有意義

Virtual Address Physical Address
4G

MMU RAM

Kernel Space kmalloc()


to create dynamic memory space
0xc0000000 3G virt_to_phys()
mmap()
User Space SetPageReserved()
0x10200000

8
Read File from Disk (1) – Using “read()”
1. AP allocate 8KB buffer in user space & exec “read()” file operation.
2. Kernel find & allocates 2 pages, initiates I/O requests for 8KB.
3. Driver send SCSI Command to read 16 sectors(8KB) & copy to allocated pages.
4. Kernel copies the requested 8KB from page cache to user buffer.

Virtual Address Physical Address


4G

MMU RAM

Kernel Space

0xc0000000 3G HARD DISK


fd=open(“file”
Read(2page) )
read(8192byte)
=8192bytes offset
User Space
Page Cache
Find 2 free pages in RAM
& Read (512bytes x 16)
9
Read File from Disk (1) – Using “mmap()”
1. AP call “mmap()” syscall to mapping file with length=8KB.
2. Kernel find & allocates 2 pages, initiates I/O requests for 8KB.
3. Driver send SCSI Command to read 16 sectors(8KB) & copy to allocated pages.
4. AP can directly access file via page buffer without allocating buffer again.

Virtual Address Physical Address


4G

MMU RAM

Kernel Space

0xc0000000 3G HARD DISK


fd=open(“file”
mmap(2page) )
read(8192byte)
=8192bytes
User Space offset
Page Cache
Find 2 free pages in RAM
& Read (512bytes x 16)
10
Why MMAP?
 Reduced memory usage : 1 memory copy
 Performance gain:
Read/write file operations & ioctl syscall by using
copy_from_user/copy_to_user make too much effort to copy large data
between Kernel space & User Space.
 “MMAP” can yield significant performance improvements. 30%

11
MMAP func.
#include <sys/mman.h>

virt_addr = mmap(start_addr, len, int prot, int flag, int fd, offset);

Returns Starting virtual address of the mapping if OK, MAP_FAILED on error


start_addr  If NULL, then the kernel chooses the address available at which to create the mapping
prot  memory protection
PROT_EXEC User Virtual Address File referenced by fd
Pages may be executed.
PROT_READ
Pages may be read. PROT_NONE
PROT_WRITE
Pages may be written.
PROT_NONE
Pages may not be accessed. PROT_READ len
PROT_WRITE

flag  MAP_SHARED return start_addr


MAP_PRIVATE ….. value of mmap
fd  should be a valid file descriptor PROT_NONE
offset
offset should be a multiple of the page size

12
MMAP with MAP_SHARED flag (Share Mapping)
1. Thanks to virtual memory management, different processes can have mapped pages in common.
2. Share this mapping with all other processes that map this object.
3. Storing to the region is equivalent to writing to the file.  Changes are shared.
Ex:
virt_addr2 = (char*)mmap(0, size,PROT_WRITE|PROT_READ,MAP_SHARED,fd,offset);
Virtual Address in Process Physical Address

MMU RAM

② READ
virt_addr1 Read(2page)
=8192bytes
Process 1 HARD DISK
Find 2 free pages in RAM
& Read (512bytes x 16) fd=open(“file”
)
Write data Write data Write data
①WRITE virt_addr2 Write(2page) offset
(8192byte) =8192bytes Page Cache msync()
Process 2 to force flush changes
 msync(virt_addr2,size, MS_SYNC); ☞
virt_addr2 must be page aligned
13
MMAP with MAP_PRIVATE flag (Private Mapping)
1. Any modifications to the data are not reflected to the file.
2. Any modifications not visible to other processes mapping the same file.  Changes are private.
3. A real life example can be found in :
glibc’s Dynamically linking libraries (*.so) are loaded by using Private Mapping.
: virt_addr2 = (char*)mmap(0, size,PROT_WRITE|PROT_READ,MAP_PRIVATE,fd,offset);

Virtual Address in Process Physical Address

3 MMU RAM
② READ 2
virt_addr1
1 Read(1page)
HARD DISK
Process 1 =4096bytes
3 fd=open(“file”

2
)

3 offset
①WRITE ! 2 1
1.“copy-on-write”
(2048byte)
virt_addr2
1 Page Cache
Process 2 2.Write(0.5page)
=2048bytes
2
MMAP with MAP_LOCKED flag
 Lock the pages of the mapped region into physical memory (avoid swapping out)
 Kernel version > 2.5.37
 Set the VMA flag of VM_LOCKED
 In the same manner of mlock()
#include <sys/mman.h> Physical Address
int mlock(const void * virt_addr, size_t len); HARD DISK
RAM
int munlock(const void * virt_addr, size_t len); fd=open(“file”
)

SWAP offset
Virtual Address Dirty Page
MMU
Reduce the size of page cache

mmap()
Clean Pages
len VMA
Write Dirty Page Swap it out!!
virt_addr

Ex:
Page Cache
virt_addr = (char*)mmap(0, size,PROT_WRITE|PROT_READ,MAP_SHARED|MAP_LOCKED,fd,offset);

15
The Usual Rules of mmap()
 The requested memory protection (prot, flags) must be
compatible with the file descriptor permissions (O_RDONLY,
etc.).
Ex: If PROT_WRITE and MAP_SHARED are given, the file must be
open for writing.
 Usually, an entire mapping is unmapped, e.g.:
i f ( ( virt_addr = mmap(NULL, length , /* . . . */ ) ) < 0)
perror("mmap error") ;
/* access memory mapped region via addr */
i f (munmap( virt_addr , length ) < 0)
perror("munmap error ") ;
 Accessing it after asuccessful munmap will (very likely) result in a
segmentation fault.
16
Mmap --- Example
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
int main( int argc,char **argv ) {
int fd ;
int filesize= getpagesize(); //sysconf(_SC_PAGESIZE)

void *virt_addr;
if ( ( fd = open( “test.bin”, O_RDONLY) ) < 0)
perror("open error”) ;
virt_addr = mmap(0, filesize, PROT_READ, MAP_SHARED | MAP_LOCKED, fd , 0) ;
if (virt_addr == MAP_FAILED) perror("mmap error”) ;
*(unsigned long*)virt_addr = 0x12345678;
msync(virt_addr,filesize,MS_SYNC)
munmap(virt_addr,filesize)
}

17
mmap - Direct Mapping to RAM
 If we want to mapping directly to RAM & access physical addresses, we
need to build a custom driver to implement mmap file operation.
Ex : We create a device file “mmapx” to replace normal file via our custom
driver – “mmapx.ko”.

fd=open(“/dev/mmapx”)
Virtual Address Physical Address
4G
mmapx
MMU RAM

Kernel Space HARD DISK

fd=open(“file”)
0xc0000000 3G

mmap() offset

User Space Physical


address = offset

18
Flow of Direct Mapping via mmap syscall
mmapx driver AP
module_init :
KERENL SPACE

USER SPACE
Create a device file
/dev/mmapx
open device file:
fd = open(“/dev/mmapx”)

call mmap syscall:


virt_addr =
mmap(0,size,PROT_READ|
mmap file operation: PROT_WRITE,MAP_SHARED|
MAP_LOCKED,fd,phyaddr);
Using remap_pfn_range to
do real memory mapping

call munmap syscall:


munmap(virt_addr ,size);
close device file:
close(fd);

time 19
What does “remap_pfn_range” do & before doing?
1. Kernel allocate a vma area. (Kernel manage user space address by using
vm_area_struct)
2. Driver get pages (physical address) of physical RAM. (via vma->vm_pgoff)
3. Driver call remap_pfn_page() to build a new “page table” to map a range of
physical addresses.

Process Descriptor fd=open(“/dev/mmapx”)


Physical Memory
mmapx
MMU RAM

Process Virtual Memory

vm_area_struct vma->vm_end remap_pfn_page()


=
address page
vm_area_struct address page
address page
vma->vm_start
vm_area_struct vma->vm_pgoff =
Physical
address
= offset
vm_area_struct
20 Link to new Page table
Using remap_pfn_range
int remap_pfn_range(struct vm_area_struct *vma,unsigned long virt_addr,
unsigned long pfn,unsigned long size, pgprot_t prot);

 Only for “reserved pages” (Out of memory management) & “physical address”
★ Kernel helps us to fill these arguments :
vma The virtual memory area into which the page range is being mapped.
virt_addr The user virtual address where mapping should begin.(vma->vm_start)
pfn Page Frame Number corresponding to the physical address.
For most users , vm->vm_pgoff contains physical address.
vma->vm_pgoff << PAGE_SHIFT is the value you need.
size  The area size being remapped. In bytes. (vma->vm_end- vma->vm_start)
prot  Protection for Pages in this VMA. Using vm->vm_page_prot .
If you don’t want the mapping area cached by CPU ,
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

21
The implement of mmap file operation
#include <linux/mm.h>
int sample_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
if (offset >=_pa(high_memory) || (filp->f_flags & O_SYNC))
vma->vm_flags |= VM_IO; This VMA MUST be a MMIO/VRAM backend memory, not
System RAM. & prevent the region being core dumped
Out of memory management – never be swapped out
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if (remap_pfn_range(vma , vma->vm_start, vma->vm_pgoff ,
vma->vm_end-vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
vma->vm_ops=&sample_vm_ops ;
return 0;
}

Ldd3
22Example : http://www.cs.fsu.edu/~baker/devices/lxr/http/source/ldd-examples/simple/simple.c
Flow of custom mmapx driver
mmapx driver AP
module_init :
Create a device file
KERENL SPACE

/dev/mmapx

USER SPACE
open device file:
fd = open(“/dev/mmapx”)

ioctl file opreation: call ioctl syscall:


Case GET_MEMORY :
phyaddr = ioctl(fd,size,GET_MEMORY)
buf=kmalloc(size)
phyaddr=virt_to_phys(buf)
call mmap syscall:
virt_addr =
mmap(0,size,PROT_READ|
PROT_WRITE,MAP_SHARED|
mmap file operation: MAP_LOCKED,fd,phyaddr);
vma->vm_flags |=VM_RESERVED

Using remap_pfn_range to do
real memory mapping call munmap syscall:
munmap(virt_addr ,size);
module_exit : close device file:
kfree(buf); close(fd);

time 23
mmap summary
 The device driver is loaded.
It defines an mmap file operation.
 A user space process calls the mmap system call.
 The process gets a starting address to read from and write to .
(depending on permissions).
 The MMU automatically takes care of converting the process virtual
addresses into physical ones.
Direct access to the hardware! No expensive read or write system calls!

24
More mmap:
1 : Operation not permitted for “/dev/mem” :
fd= open("/dev/mem", O_RDWR | O_SYNC);
Virtaddr=mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE,MAP_SHARED,fd,phyaddr);
not supported in defult for Linux Kernel 2.6.25↑ expect for disabling
CONFIG_STRICT_DEVMEM on kernel building.
2. We need to set page reserved before doing real mapping(remap_pfn_range).
Linux 2.4 ↓  Using mem_map_reserve() to set each pages as PG_Reserved.
Linux 2.6.0~2.6.18 ↓  Using SetPageReserved() to set each pages as PG_Reserved.
Linux 2.6.25 ↑  Setting vm_flags as VM_RESERVED to avoid swapping out.
3. We do not need use “msync()” to force flush changes in our AP via custom mmapx
driver. Because there is no “Page-Cache” implemented in our custom mmapx driver.
And msync will call fsync file operation, so we also do not implement fsync.
4. A buffer allocated by get_user_pages() does not need mlock() function.

25
THANK YOU

You might also like