linux内存分配与io内存
系统内存分区图:

一,页分配器
void *kmalloc(size_t size, int flags); kmalloc()的底层依赖_ _get_free_pages()实现,中断处理函数、tasklet 和内核定时器等非进程上下文中不能阻塞,此时驱动应当使用 GFP_A TOMIC 标志来申请内存。_ _get_free_pages()系列函数/宏包括 get_zeroed_page()、_ _get_dma_page(),_ _get_free_page()和_ _get_free_pages()。
二,slab分配器
1.创建 slab 缓存
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags,void (*ctor)(void*, struct kmem_cache *, unsigned long), void (*dtor)(void*, struct kmem_cache *, unsigned long));
2,分配 slab 缓存。void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
上述函数在 kmem_cache_create()创建的 slab 后备缓冲中分配一块并返回首地址指针。
3.释放 slab 缓存。void kmem_cache_free(struct kmem_cache *cachep, void *objp); 上述函数释放由 kmem_cache_alloc()分配的缓存
4.收回 slab 缓存。int kmem_cache_destroy(struct kmem_cache *cachep);
1 /*创建 slab 缓存*/
2 static kmem_cache_t *xxx_cachep;
3 xxx_cachep = kmem_cache_create("xxx", sizeof(struct xxx),
4 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
5 /*分配 slab 缓存*/
6 struct xxx *ctx;
7 ctx = kmem_cache_alloc(xxx_cachep, GFP_KERNEL);
8 ...//使用 slab 缓存
9 /*释放 slab 缓存*/
10 kmem_cache_free(xxx_cachep, ctx);
11 kmem_cache_destroy(xxx_cachep);
三,IO内存
1.void *ioremap(unsigned long offset, unsigned long size); 内核中访问 I/O 内存之前,需首先使用 i将设备所处的物理地址映射到虚拟地址,ioremap()与 vmalloc()类似, 也需要建立新的页表, 但是它并不进行 vmalloc()中所执行的内存分配行为。ioremap()返回一个特殊的虚拟地址,该地址可用来存取特定的
物理地址范围。通过 ioremap()获得的虚拟地址应该被 iounmap()函数释放
2.void iounmap(void * addr);
读 I/O 内存。unsigned int ioread8(void *addr); unsigned int ioread16(void *addr); unsigned int ioread32(void *addr);
写 I/O 内存。void iowrite8(u8 value, void *addr); void iowrite16(u16 value, void *addr); void iowrite32(u32 value, void *addr);
读一串 I/O 内存,写一串 I/O 内存void iowrite32_rep(void *addr, const void *buf, unsigned long count);。复制 I/O 内存void memcpy_fromio(void *dest, void *source, unsigned int count);。设置 I/O 内存void memset_io(void *addr, u8 value, unsignedint count);。
申请和释放 I/O 端口 I/O 内存申请
把 I/O 端口映射到内存空间。void *ioport_map(unsigned long port, unsignedint count); 过这个函数,可以把 port 开始的 count 个连续的 I/O 端口重映射为一段“内存空间” 。 然后就可以在其返回的地址上像访问 I/O 内存一样访问这些 I/O 端口。 当不再需要这种映射时,需要调用下面的函数来撤销。void ioport_unmap(void *addr);
Linux 内核提供了一组函数用于申请和释放 I/O 端口 struct resource *request_region(unsigned long first, unsigned long n, const char *name);void release_region(unsigned long start, unsigned long n);
IO端口的访问:

Linux 内核也提供了一组函数用于申请和释放 I/O 内存的范围。struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
void release_mem_region(unsigned long start, unsigned long len);
io 内存的访问:

浙公网安备 33010602011771号