1. 内核空间和用户空间 1G ~ 3G 用户空间使用的地址范围(3G)
3G ~ 4G 内核空间使用的地址范围(1G)
2. 内存的申请
(1)用户空间的内存申请: malloc free
(2)内核空间的内存申请:
a.
__get_free_pages() 与void free_page(unsigned long addr)
extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
gfp_mask : 内存申请的标识
#define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH)
#define GFP_ATOMIC (__GFP_HIGH)
#define GFP_NOIO (__GFP_WAIT)
#define GFP_NOFS (__GFP_WAIT | __GFP_IO)
#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS)
GFP_KERNEL(带睡眠的) :含义是在内核空间申请内存,如果内存不足时,进程会睡眠等待,因此不能在自旋锁和中断上下文中使用
GFP_ATOMIC (不带睡眠的):含义是在内核空间申请内存,如果内存不足时,则不等待立即返回
order :表示的是多少页 ,order允许的最大值是10(即1024页)或者 11(即2048页),
依赖于具体的硬件平台
调用者指定所需整页的阶数作为参数之一来请求(按照页进行分配)
所申请的页将会被加入内核空间
所分配的物理RAM空间是连续的
b . kmalloc 和 kfree
内存的申请: static __always_inline void *
kmalloc(size_t size, gfp_t flags)
size : 当kmalloc申请内存空间时,内核就会将一个刚好足够大的空闲内存块分配出来。
比如要申请100字节,kmalloc就会返回一个128字节的内存块
在4k字节大小页面的系统上,分配的最小内存块是32字节,最大128k字节
内存的释放: void
kfree(const void *objp)
objp : @objp: pointer returned by kmalloc.
c . vmalloc 和vfree
内存的申请: void *
vmalloc(unsigned long size)
size: 申请内存的大小
内存的释放: void
vfree(const void *addr)
addr : memory base address
d. 内核启动前,手动预留一块大内存
e. 内存池 slab
3. IO端口与IO内存
IO端口: 一般用在X86系统上,有专用的指令访问IO端口的设备,
IO内存: 一般在ARM,PowerPC,MIPS,外设会占用一个总线地址,这个地址就是IO内存地址
4. IO内存映射函数 ioremap函数
ioremap映射函数与取消映射函数
iounmap
a.依赖头文件: <asm/io.h>
b. 把一个物理地址映射成一个虚拟地址,在内核中可以访问这个虚拟地址
static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
{
return (void __iomem*) (unsigned long)offset;
}
offset : 物理地址的开始
size : 需要转换的大小
返回值: void __iomem *
c . 取消映射
void iounmap(volatile void __iomem *addr)
addr :要取消映射的开始地址
5. IO内存地址的访问
读一个字节:
unsigned int ioread8(void *addr);
unsigned int readb(void *addr)(早期内核版本,以后可以被淘汰用法)
读2个字节
unsigned int ioread16(void *addr);
unsigned int readw(void *addr)
读4个字节
unsigned int ioread32(void *addr);
unsigned int
readl(void *addr)
写一个字节:
void iowrite8(u8 value, void *addr);
void writeb(u8 value, void *addr);
写2个字节:
void iowrite16(u16 value, void *addr);
void writew(u16 value, void *addr);
写4个字节
void iowrite32(u32 value, void *addr);
void
writel(u32 value, void *addr);