Device drivers can dynamically allocate memory via the many memory management interfaces that Linux provides. This chapter describes memory interfaces that return addresses that can be mapped as direct memory access (DMA) addresses.
Device drivers should never try to use kernel text or data for DMA. It is also inappropriate to use memory areas allocated via the vmalloc routine as a DMA area, even though it can be done. The vmalloc routine allows the driver to allocate a large contiguous virtual address range. However, the address cannot be used as input to any of the DMA map routines.
Device drivers can use the __get_free_page() routine to allocate a page of memory that can be mapped as a DMA address, as in the following example:
{
char *buf;
buf = (char*) __get_free_page(GFP_KERNEL);
} |
This routine returns a value of type unsigned long. Memory is always allocated from the node that the thread is executing first.
Memory areas allocated via this interface are region 7 addresses and identity mapped addresses. These kernel virtual addresses can be used as input to any of the PCI DMA map routines.
Device drivers can request memory on a specific node. The rationale for a specific request would be data placement for performance reasons. If you need to allocate memory on a specific node, use the following interface:
struct page * alloc_pages_node(int node_id, unsigned int gfp_mask, unsigned int order) |
The address returned in struct page * can be used as input to any of the PCI DMA map routines, as in the following example:
struct page * my_page; my_page = alloc_pages_node(node_id, gfp_mask, order); dma_addr = pci_map_single(my_dev, my_page -> virtual, size, direction); |
| Note: The interface is available only if CONFIG_NUMA is configured on, as in SGI Altix 3000 systems. |
Device drivers can ask for memory with any arbitrary length by using the following routine:
void * kmalloc (size_t size, int flags); |
This routine returns region 7 and identity mapped kernel virtual addresses. This kernel virtual address can also be used as input into any of the PCI mapping routines.
The advantage of this routine is that it provides a single starting virtual and physical address that is contiguous. However, if the kernel cannot find a contiguous area large enough, this call will fail.
It is very important for drivers, when reading or writing into the user area, to verify first that the specified user address is valid. Linux provides two routines that enable kernel level code for verification.
For verification within the user virtual area:
int access_ok(type, user_address, size); |
For verification when the area is actually mapped with the correct access rights:
int verify_area(type, user_address, size); |
Where:
| type: | VERIFY_READ - Verify for read access VERIFY_WRITE - Verify for read/write access | |
| user_address: | User's virtual address | |
| size: | Size of the area in bytes |
The following routines write or read a a single value to or from the user area. The size of the single value depends on the size of ( *pointer):
int put_user(value, pointer) int get_user(value, pointer) |
The following optimized routines write or read the given number of byte count to or from the user area:
int copy_to_user(user_address, kernel_address, byte_count); int copy_from_user(kernel_address, user_address, byte_count); |
The following routines provide string manipulation from the user area:
long strlen_user(user_address); long strnlen_user(user_address, count); long strncpy_from_user(kernel_address, user_address, count); |
An important point to note is that all of these user area access routines actually perform access verification first. The following corresponding set of routines are available to the driver, which do not perform any access verifications. The names of these routines are the same as the precedint routines but with a double underscore (__) prepended.
int __put_user(value, pointer) int __get_user(value, pointer) int __copy_to_user(user_address, kernel_address, byte_count) int __copy_from_user(kernel_address, user_address, byte_count) long __strlen_user(user_address) long __strnlen_user(user_address, count) long __strncpy_from_user(kernel_address, user_address, count) |
Sometimes, kernel level routines require calls to system call handlers, as do user level routines. However, all of these handlers expect addresses in the call to be user addresses. A kernel level routine calling a system call interface with a kernel virtual address will definitely fail when the system call interface performs address validation. For example, the following call will fail when sys_open performs any address verification:
sys_open("/dev/mydriver_config_file", O_RDONLY, 0); |
Linux provides the following set of routines that, in effect, disable address validity checking:
current_segment = get_fs();
set_fs(active_segment); |
The current_segment and active_segment values are either KERNEL_DS or USER_DS. If the current data segment is KERNEL_DS, the access verification routines do not perform any verification. If the current data segment is USER_DS, the access routines verify that the specified user addresses are valid.
Therefore, if your driver requires negation of all address verification, use the following code:
mm_segment_t current_segment;
current_segment = get_fs(); /* Save current segment */
set_fs(KERNEL_DS);
fd = sys_open("/dev/mydriver_config_file", O_RDONLY, 0);
set_fs(current_segment) /* Restore saved segment */ |
In general, device drivers allocate kernel buffers as intermediate transfer areas to move data between the user area and an external device. Sometimes, but not always, it can be more performance-efficient to transfer data directly between the user area and the external device, without incurring the additional CPU time for copying between kernel buffers and the user area, and other such activities. Linux provides the Kernel IO Buffer (kiobuf) facility, which allows a user area to be mapped to kernel virtual space. Once this mapping is performed, kernel virtual addresses can be DMA mapped to allow external devices to write directly into the mapped user area.
kiobuf provides the following interfaces:
Allocate and free kiobuf structures:
int alloc_kiovec(int number_pages, struct kiobuf **iovec); void free_kiovec(int number_pages, struct kiobuf **iovec); |
Map/unmap user addresses to kernel virtual addresses:
int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len) void unmap_kiobuf (struct kiobuf *iobuf) |
Lock the pages in the kiobuf:
int lock_kiovec(int nr, struct kiobuf *iovec[], int wait) int unlock_kiovec(int nr, struct kiobuf *iovec[]) |
For more information regarding this feature, see Linux Device Drivers, chapter 13, “MMap and Dma.”