"Linux Device Drivers", chapter 15th, Memory Mapping and Dma--note

Source: Internet
Author: User

  • Simple Introduction
    • Many types of driver programming require knowledge of how some virtual memory subsystems work
    • When it comes to more complex, performance-demanding subsystems, the content discussed in this chapter will sooner or later be used
    • The contents of this chapter are divided into three parts
      • Describe the implementation process for MMAP system calls
      • Describes how to access the memory pages of user space directly across borders
      • Describes direct memory access (DMA) I/O operations, which gives peripherals the ability to directly access system memory
  • Memory Management for Linux
    • Address Type
        • Linux is a virtual memory system, which means that the address used by the user program is not equivalent to the physical address used by the hardware
        • has virtual memory, and programs executed in the system can allocate much more memory than physical memory, Even a single process can have many other virtual address spaces than the system's physical memory
        • The following is a list of address types used by Linux
          • user virtual address
            • This is the general address that the user space program can see
          • Physical Address
            • This address is used between the processor and the system memory
          • bus address
            • The address is always in the perimeter Between lines and memory, usually they are the same as the physical address used by the processor
          • kernel logical addresses
            • kernel logical addresses make up the general address space of the kernel
            • in most architectures. The logical address differs from the physical address associated with it, with only a fixed offset between them
            • the memory returned by Kmalloc is the kernel logical address
          • kernel virtual address
            • and the kernel logical address is in the same place. They all map the address of the kernel space to the physical address. The mapping of the
            • kernel virtual address to the physical address does not have to be linear one-to-one
            • all logical addresses are kernel virtual addresses. But very many kernel virtual addresses are not logical addresses
            • Vmalloc allocated memory has a virtual address
        • <asm/page.h>
            __PA ()
            • returns its corresponding physical address
          • __va ()
            • maps the physical address back to the logical address, but this is only valid for low-end memory pages
    • Physical Address and Page
      • The physical address is divided into discrete units. called a page
      • <asm/page.h>
        • Page_size
      • Most systems now use 4,096 bytes per page
    • High-end and low-end memory
      • Use 32-bit systems to address only 4GB of memory
      • The kernel cuts 4GB of virtual address space into user space and kernel space, and a typical cut is to allocate 3GB to user space. 1GB allocated to kernel space
      • Low-end memory
        • Logical address memory that exists on the kernel space
      • High-end memory
        • Memory that does not exist in logical addresses
    • Memory Mapping and page structure
      • <linux/mm.h>
      • struct page
        • atomic_t count;
          • A count of the number of visits to the page.

            When the count value is 0 o'clock, the page is returned to the spare list

        • void *virtual;
          • Assume that the page is mapped. The kernel virtual address of the page, or null if it is not mapped
        • unsigned long flags;
          • A series of flags describing the state of a narrative page
          • Pg_locked indicates that the in-memory page is locked
          • Pg_reserved indicates that the memory management system is forbidden to visit this page
      • struct page *virt_to_page (void *kaddr);
      • struct page *pfn_to_page (int pfn);
        • Returns the page structure pointer for the given page frame number
      • void *page_address (struct page *page);
        • Returns the kernel virtual address of the page
      • <linux/highmem.h>
        • <asm/kmap_types.h>
        • void *kmap (struct page *page);
          • For low-end memory pages, return the logical address of the page
          • For high-end memory, create special mappings in the dedicated kernel address space
        • void Kunmap (struct page *page);
        • void *kmap_atomic (struct page *page, enum km_type type);
        • void kunmap_atomic (void *addr, enum km_type type);
    • Page table
      • The processor must use some mechanism to convert the virtual address to the corresponding physical address. Such a mechanism is called a page table
      • It is basically a multi-layered tree-shaped structure. Structured data includes mapping of virtual addresses to physical addresses and associated flag bits
    • Virtual Memory Area
      • Virtual memory Area (VMA) is used to manage kernel data structures in different areas of the process address space
      • Memory mappings for processes include the following areas
        • The code area of the program that can be run
        • Multiple data areas, including initialization data, non-initialized data, and program stacks
        • The area corresponding to the memory map for each activity
      • /proc/<pid>/maps
        • Start-end Perm offset Major:minor inode image
      • VM_AREA_STRUCT structure
        • <linux/mm.h>
        • struct VM_AREA_STRUCT
          • unsigned long vm_start;
          • unsigned long vm_end;
          • struct file *vm_file;
          • unsigned long vm_pgoff;
          • unsigned long vm_flags;
          • struct Vm_operations_struct *vm_ops;
          • void *vm_private_data;
        • struct VM_OPERATIONS_STRUCT
          • void (*open) (struct vm_area_struct *vma);
          • void (*close) (struct vm_area_struct *vma);
          • struct page * (*nopage) (struct vm_area_struct *vma, unsigned long address, int *type);
          • Int (*populate) (struct vm_area_struct *vm, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);
    • Memory-mapped processing
      • <linux/sched.h>
        • struct MM_STRUCT
      • current->mm

  • Mmap Device operation
    • Memory mapping provides the ability for a user program to directly access device memory
    • Mapping a device means that a piece of memory in the user space is associated with the device memory.
    • Mmap abstractions like serial ports and other stream-oriented devices cannot be
    • Must be mapped in page_size units
    • The Mmap method is part of the file_operations structure
    • Mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
    • Int (*mmap) (struct file *filp, struct vm_area_struct *vma);
    • There are two ways to create a page table
      • Use the Remap_pfn_range function all at once to establish
      • Create a page table each time by Nopage VMA method
    • Using Remap_pfn_range
      • int Rempa_pfn_range (struct vm_area_struct *vma, unsigned long virt_addr, unsigned long pfn, unsigned long size, pgprot_t p ROT);
      • int Io_remap_page_range (struct vm_area_struct *vma, unsigned long virt_addr, unsigned long phys_addr, unsigned long size, pgprot_t prot);
      • Vma
        • Virtual Memory Area
      • Virt_addr
        • The starting user virtual address when mapping again
      • Pfn
        • The page frame number corresponding to the physical memory. Virtual memory will be mapped to this physical memory
        • The page frame number simply shifts the physical address to the right page_shift bit
      • Size
        • In bytes
      • Prot
        • New VMA required "Protection (protection)" Property
    • A simple implementation
      • Drivers/char/mem.c
      • Remap_pfn_range (VMA, Vma->vm_start, Vm_.vm_pgoff, Vma->vm_end–vma->vm_start, Vma->vm_page_prot)
    • Join the operation for VMA
      • struct Vm_operations_struct simple_remap_vm_ops = {. open = Simple_vma_open,. Close = Simple_vma_close,}
    • Mapping memory using Nopage
      • Suppose you want to support MREMAP system calls. You must implement the Nopage function
      • struct page * (*nopage) (struct vm_area_struct *vma, unsigned long address, int *type);
      • Get_page (struct page *pageptr);
      • static int simple_nopage_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))
          • Vm->vm_flags |= Vm_io
        • Vm->vm_flags |= vm_reserved;
        • Vm->vm_ops = &simple_nopage_vm_ops;
        • Simple_vma_open (VMA);
        • return 0;
      • }
      • struct page *simple_vma_nopage (struct vm_area_struct *vma, unsigned long address, int *type)
      • {
        • struct page *pageptr;
        • unsigned long offset = Vma->vm_pgoff << page_shift;
        • unsigned long physaddr = Address–vma->vm_start + offset;
        • unsigned long pageframe = physaddr >> page_shift;
        • if (!pfn_valid (pageframe))
          • return nopage_sigbus;
        • Pageptr = Pfn_to_page (pageframe);
        • Get_page (PAGEPTR);
        • if (type)
            • Type = Vm_fault_minor;
        • return pageptr;
      • }
    • Mapping Ram once again
      • One limitation to the Remap_pfn_range function is that it only has access to the physical address of the reserved page and beyond the physical memory
      • Remap_pfn_range don't agree to map regular addresses again
      • Mapping RAM once again using the Nopage method
        • Using Vm_ops->nopage to process one page error at a time
    • Mapping the kernel virtual address again
      • page = Vmalloc_to_page (pageptr);
      • Get_page (page);
  • Run Direct I/O interview
    • Assume that the amount of data that needs to be transferred is large. Transfer the data directly. Without the need for additional data manipulation from the kernel space, this will greatly improve the speed of
    • The overhead of setting up direct I/O is huge
      • Using direct I/O requires write system call to run synchronously
      • The application cannot be stopped until each write operation is complete
    • <linux/mm.h>
      • int get_user_pages (struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int force, Stru CT page **pages, struct vm-area_struct **vmas);
        • Tsk
          • A pointer to a task that runs I/O, which is almost current
        • Mm
          • Pointer to a memory management structure describing the mapped address space
          • For the driver. This number is always current->mm
        • Force
          • Assume that write is nonzero. Write permissions on mapped pages
          • The driver is always set to 0 for this parameter
        • Pages
          • Assuming a successful invocation, pages contains a list of pointers describing the page structure of the user space buffer.
        • VMAs
          • Assuming the call succeeds, VMAs includes a pointer to the corresponding VMA
    • Devices that use direct I/O typically use DMA operations
    • Once the direct I/O operation is complete, the user memory page must be freed
    • <linux/page-flags.h>
      • void Setpagedirty (struct page *page);
    • void page_cache_release (struct page *page);
    • asynchronous I/O
      • <linux/aio.h>
      • ssize_t (*aio_read) (struct KIOCB *iocb, char *buffer, size_t count, loff_t offset);
      • ssize_t (*aio_write) (struct KIOCB *iocb, const char *buffer, size_t count, loff_t offset);
      • Int (*aio_fsync) (struct KIOCB *iocb, int datasync);
      • int IS_SYNC_KIOCB (struct KIOCB *IOCB);
      • int aio_complete (struct KIOCB *IOCB, long res, long res2);
  • Direct Memory Interview
    • DMA is a hardware mechanism that agrees to transfer their I/O data directly between the perimeter device and the main memory. Without the need for the system processor to participate
    • Using such a mechanism can greatly increase the throughput of communication with the device
    • DMA Transfer Data Overview
      • There are two ways to trigger the transfer of data
        • Software requests for data
          • When the process calls read, the driver function allocates a DMA buffer and lets the hardware transfer the data into this buffer, and the process is in a sleep state
          • The hardware writes data to the DMA buffer when the write is complete. Create an interrupt
          • The interrupt handler obtains the input data and answers the interrupt. And the process is awakened, and the process can now read the data
        • Hardware asynchronously passes data to the system
          • The hardware interrupts, announcing the arrival of new data
          • The interrupt handler allocates a buffer and tells the hardware where to transfer the data
          • Peripheral devices write data to buffer, resulting in another interrupt
          • The handler distributes the new data. Wake up no matter what the related process and then run cleanup work
    • Allocating a DMA buffer
      • The main problem with DMA buffers is when they are larger than one page. They must occupy the physical page of the connection, because the device uses ISA or PCI system Bus data transfer, both of which use physical addresses
      • DIY Assignment
        • The Get_free_pages function can allocate up to a few m bytes of memory, but for a larger number of requests. Even requests that are far less than 128KB generally fail because the system memory is full of memory fragmentation
        • When the kernel cannot return the requested amount of memory or needs to exceed 128KB of memory, in addition to returning-enomem, another method is to allocate memory at boot time or to retain the top physical RAM for the buffer
        • Another method is to use the Gfp_nofail allocation flag to allocate memory for the buffer
    • Bus Address
      • Device drivers that use DMA will communicate with the hardware that is connected to the bus interface, the hardware uses the physical address, and the program code uses the virtual address
      • <asm/io.h>
        • unsigned long virt_to_bus (volatile void *address);
        • void *bus_to_virt (unsigned long address);
    • Universal DMA Layer
      • The kernel provides a DMA layer independent of the bus architecture
      • <linux/dma-mapping.h>
      • Dealing with complex hardware
        • int dma_set_mask (struct device *dev, u64 mask);
          • The mask displays bits corresponding to the ability of the device to address
          • Assuming that Dma_set_mask returns 0, the DMA is not available for the device
      • DMA Mapping
        • A DMA mapping is a combination of the DMA buffers to be allocated and the device accessible addresses generated for the buffer
        • The DMA mapping establishes a new struct type--dma_addr_t to represent the bus address
        • The length of time that is expected to be retained based on the DMA buffer. PCI code distinguishes between two types of DMA mappings
          • Consistent DMA Mapping
            • Mappings of such types exist in the driver life cycle
            • The buffer for the consistency map must be accessible at the same time by the CPU and peripherals
            • The overhead of establishing and using a consistency map is very large
          • Streaming DMA Mapping
            • Typically, flow mapping is established for individual operations
            • Kernel developers recommend that you use streaming mappings as much as possible and then consider consistency mappings
              • In systems that support map registers, each DMA map uses one or more mapping registers on the bus
              • In some hardware, streaming mapping can be optimized. But the optimized method is not valid for consistency mapping
      • Establishing a consistent DMA mapping
        • void *dma_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, int flag);
          • The return value is the kernel virtual address of the buffer
          • Associated bus address, saved in Dma_handle
        • void dma_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle);
      • DMA Pool
        • DMA pool is a mechanism for generating small, consistent DMA mappings
        • <linux/dmapool.h>
          • struct Dma_pool *dma_pool_ Create (const char *name, struct device *dev, size_t size, size_t align, size_t allocation);
            • allocation is nonzero to indicate that memory boundaries cannot exceed allocation
          • void Dma_pool_destroy (struct dma_pool *pool);
          • void *dma_pool_alloc (struct dma_pool *pool, int mem_flags, dma_addr_t *handle); The address of the DMA buffer returned by
            • is the kernel virtual address
          • void Dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t addr);
      • to establish a streaming DMA mapping
        • When a streaming mapping is established. The direction of the kernel data flow must be told
        • enum dma_data_direction
          • dma_to_device
          • dma_from_device
          • D Ma_bidirectional
          • dma_none
        • dma_addr_t dma_map_single (struct device *dev, void *buffer , size_t size, enum dma_data_direction direction);
        • void Dma_unmap_single (struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction);
        • The
        • has several important principles for streaming DMA mapping
          • buffers can only be used for this kind of transfer. That is, the direction of its transmission matches the direction given at the time of mapping WFHG
          • Once the buffer is mapped, it will belong to the device, not the processor
          • during the DMA is active, you cannot undo the buffer mapping, otherwise it will severely damage the stability of the system
          /li>
        • void dma_sync_single_for_cpu (struct device *dev, dma_handle_t bus_addr, size_t size, enum dma_data_direction di rection);
        • void Dma_sync_single_for_device (struct device *dev, dma_handle_t bus_addr, size_t size, enum dma_data_direction direction);
      • Single-page streaming mapping
        • dma_addr_t dma_map_page (struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction);
        • void Dma_unmap_page (struct device *dev, dma_addr_t dma_address, size_t size, enum dma_data_direction direction);
      • Scatter/focus Mapping
        • This is a special kind of streaming DMA mapping
        • If there are several buffers, they need two-way data transfer with the device
        • There are several ways to create this situation.
          • Generated from RAEDV or Writev system calls
          • Disk I/O requests from the cluster are generated
          • Generated from the list of page lists in the mapped kernel I/O buffers
        • Many devices can accept a scatter table of a pointer array, as well as its length, and then transmit all of them in a single DMA operation.
        • The first step in mapping a decentralized table is to create and populate an array of scatterlist structures describing the transmitted buffer.
        • <linux/scatterlist.h>
        • struct scatterlist
          • struct page *page;
          • unsigned int length;
          • unsigned int offset;
        • int Dma_map_sg (struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction);
          • Nents is the number of scattered table portals that are passed in
          • The return value is the number of DMA buffers to be transferred
        • The driver should transmit every buffer returned by the DMA_MAP_SG function
        • dma_addr_t sg_dma_address (struct scatterlist *sg);
        • unsinged int Sg_dma_len (struct scatterlist *sg);
        • void Dma_unmap_sg (struct device *dev, struct scatterlist *list, int nents, enum dma_data_direction direction);
          • Nents must be the number of entries previously passed to the DMA_MAP_SG function
        • void dma_sync_sg_for_cpu (struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction);
        • void Dma_sync_sg_for_device (struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction);
      • PCI Dual Address cycle mapping
        • Typically, the DMA support layer uses a 32-bit bus address. It is constrained by the DMA mask of the device
        • The PCI bus also supports 64-bit address mode. Dual address cycle (DAC)
        • Assuming that the device needs to use large buffers placed in high-end memory, consider implementing DAC support
        • <linux/pci.h>
        • int Pci_dac_set_dma_mask (struct Pci_dev *pdev, u64 mask);
          • Returns 0 o'clock. Ability to use DAC addresses
        • dma64_addr_t PCI_DAC_PAGE_TO_DMA (struct pci_dev *pdev, struct page *page, unsigned long offset, int direction);
          • Direction
            • Pci_dma_todevice
            • Pci_dma_fromdevice
            • Pci_dma_bidirectional
        • void Pci_dac_dma_sync_single_for_cpu (struct Pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction);
        • void Pci_dac_dma_sync_single_for_device (struct Pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction);
    • ISA Device's DMA
      • ISA bus agrees on two DMA transfers: local (native) DMA and ISA bus control (Bus-master) DMA
      • Local DMA uses the standard DMA controller circuitry on the motherboard to drive the signal line on the ISA bus
      • ISA Bus control DMA is completely controlled by peripheral devices
      • There are three implementations involving DMA transfer data on the ISA bus
        • 8237 DMA Controller (DMAC)
        • Peripheral equipment
          • The DMA request signal must be activated when the device is ready to transfer data
        • Device drivers
          • There is very little work required to complete the driver, it is only responsible for providing the direction of the DMA controller, the bus address, the size of the traffic, etc.
      • Brochure DMA
        • <asm/dma.h>
          • int REQUEST_DMA (unsigned int channel, const char *name);
            • Returning 0 indicates a successful run
          • void FREE_DMA (unsigned int channel);
      • Communicating with the DMA controller
        • unsigned long claim_dma_lock ();
        • The information that must be loaded into the controller consists of three parts: the address of the RAM, the number of atomic items that must be transmitted, and the direction of the transmission
        • void Set_dma_mode (unsigned int channel, char mode);
          • Mode
            • Dma_mode_read
            • Dma_mode_write
            • Dma_mode_cascade
              • Release control of the bus
        • void set_dma_addr (unsigned int channel, unsigned int addr);
        • void Set_dma_count (unsigned int channel, unsigned int count);
        • void DISABLE_DMA (unsigned int channel);
        • void ENABLE_DMA (unsigned int channel);
        • int get_dma_residue (unsigned int channel);
          • Returns the number of bytes that have not yet been transferred
        • void clear_dma_ff (unsigned int channel);

"Linux Device Drivers", chapter 15th, Memory Mapping and Dma--note

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.