Chinaunix首页 | 论坛 | 博客
  • 博客访问: 337595
  • 博文数量: 92
  • 博客积分: 2500
  • 博客等级: 少校
  • 技术积分: 960
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-21 19:38
文章分类

全部博文(92)

文章存档

2010年(71)

2009年(21)

我的朋友

分类: 嵌入式

2010-04-15 16:44:18

内存与I/O访问

CPU对外设I/O端口地址的编址方式有两种:

1.       I/O映射方式(I/O-mapped

2.       内存映射方式(Memory-mapped

具体采用哪一种方式取决于CPU的体系结构。

x86体系中为外设专门实现了与RAM内存地址不同的一个单独的地址空间,也就是I/O映射方式。可以使用outb,inb等函数直接操作这些I/O端口。

ARM体系中,外设I/O端口具有与内存相同的物理地址,这样的方式是内存映射方式。

我这里主要学习了内存映射方式(Memory-mapped):

外设的I/O内存资源的物理地址是已知的,由硬件的设计决定。但是CPU通常并没有为这些已知的外设I/O内存资源的物理地址预定虚拟地址,驱动程序不能直接通过物理地址访问I/O内存资源,而必须将他们映射到核心虚拟地址空间中(通过也表),然后才能根据映射所得到的核心虚地址范围,通过访问指令访问这些I/O内存资源。Linuxio.h同文件中声明了函数ioremap()用来将I/O内存资源的物理地址映射到核心虚拟地址空间(3GB~4GB

 

Void *ioremap(unsigned ong phys_addr, unsigned long size, unsigned long flags);

//物理地址映射到核心虚地址空间

Void iounmap(void *addr)

//取消ioremap所做的地址映射

看一段源码:

static int  button_init(void)

{

       int ret;

  int result; //add by yoyo

       gpecon = ioremap(0x56000040, 0x04);//得到相应IO口的虚拟地址,下同

       gpedat = ioremap(0x56000044, 0x04);

       gpfcon = ioremap(0x56000050, 0x04);

       gpfdat = ioremap(0x56000054, 0x04);

       gpgcon = ioremap(0x56000060, 0x04);

       gpgdat = ioremap(0x56000064, 0x04);

………..

}

static void __exit button_exit(void)

{

       disable_irqs();

       free_irqs();

 

       iounmap(gpecon);  iounmap( gpedat);

       iounmap(gpfcon);

       iounmap(gpfdat);

       iounmap(gpgcon);

    iounmap(gpgdat);

……………

}

 

用户空间内存动态申请:

在用户空间动态申请内存的函数为malloc(),释放函数为free()

Char * function(void)

{

       char *p;

       p = (char * )malloc(…);

       if(p==NULL)

       ….;

       ….//一系列针对p的操作

}

 

在某处调用function(),用完function()中动态申请的内存后将其free,如下:

char *q= function();

….

free(q);

 

内核空间内存动态申请:

Linux内核空间申请内存涉及的函数主要包括kmalloc(), __get_free_pages()vmalloc()

1.Kmalloc()

Void * kmalloc(size_t size, int flags);

Size:分配的块的大小

Flags:分配标志:  GFP_KERNEL:含义是在内核空间的进程中申请内存。Kmalloc()的底层依赖__get_free_pages()实现,使用GFP_KERNEL标志申请内存时,若暂时不能满足,则进程会睡眠等待页,即会引起阻塞,因此不能在中断上下文或持有自旋锁的时候使用GFP_KERNEL申请内存。

                            GFP_ATOMIC:申请内存时,若不存在空闲页,则不等待,直接返回,可用在中断处理函数,tasklet和内核定时器等进程上下文中

 

2.__get_free_pages()

__get_free_pages()系列函数/宏是kmalloc()实现的基础。

__get_free_pages(unsigned int flags, unsigned int order);

该函数可分配多个页并返回分配内存的首地址,分配的页数为2^order

释放函数为:

Void free_page()void free_pages()

 

3.Vmalloc()

l         Vmalloc()远远大于__get_free_pages()的开销,为了完成vmalloc(),新的页表需要被建立。因此,只是调用vmalloc()来分配少量的内存(如1页)是不妥的。

l         Vmalloc()不能用于原子上下文,因为它的内部实现使用了标志为GFP_KERNELkmalloc()

l         使用vmalloc()函数的一个例子函数是creat_module()系统调用,它利用vmalloc()函数来获取被创建模块需要的内存空间。

 

 

 

阅读(1239) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~