ioremap内存映射 始终不能访问内存 求解

isolated_bb 2011-03-07 03:29:41
ioremap内存映射,修改了数次,还是不能正常访问寄存器,基本问题是可以加载模块,但是只要lsmod就会出现段错误
unable to handle kernel paging request at virtual address 7fXXXXXX
望高手指教!!!

#include <asm/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/gpio.h>

static int led_major;
static void *base;
#define LED_CONTROLLER_BASE 0x56000050
#define led_all_off 0
#define led_all_on 1
#define DEVICE_NAME "zx_led"
#define LED_CON (*(volatile u32*)(LED_CONTROLLER_BASE))
#define LED_DAT (*(volatile u32*)(LED_CONTROLLER_BASE + 4))
#define LED_UP (*(volatile u32*)(LED_CONTROLLER_BASE + 8))
#define LED_MEM_LEN 0x0c
static int led_open(struct inode *inode,struct file *file)
{
printk("the led driver is open\n");
return 0;
}
static int led_close(struct inode *inode,struct file *file)
{
printk("the led driver is close\n");
return 0;
}
static int led_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
switch(cmd)
{
case led_all_off:
//iowrite16(0x00,base + 0x04);
iowrite16((ioread16(base + 0x04)&0xff)|0x0,base + 0x04);
break;
case led_all_on:
iowrite16(0x0f00,base + 0x04);
iowrite16((ioread16(base + 0x04)&0xff)|0xff00,base + 0x04);
break;
default:
return -EINVAL;
}
return 0;
}

static struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.ioctl = led_ioctl,
.release= led_close,
};

static struct class *led_class;
static int led_init(void)
{
printk("led initialize\n");
led_major = register_chrdev(0, DEVICE_NAME, &led_fops);
if(led_major < 0)
{
printk("can't creat led_major\n");
return led_major;
}
printk("register zhengxu_led Driver OK! Major = %d\n", led_major);
led_class = class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(led_class))
{
printk("led_class create is failed\n");
return -1;
}
printk("class_create is ok\n");
device_create(led_class, NULL, MKDEV(led_major, 0), NULL, DEVICE_NAME);
printk("initialize is sucessful\n");
request_mem_region(LED_CONTROLLER_BASE,LED_MEM_LEN,"zx_led");
base=ioremap_nocache(LED_CONTROLLER_BASE,LED_MEM_LEN);
printk("%lx\n",base);
printk("ioremap is sucessful\n");
if(base < 0)
{
printk("ioremap is failed\n");
}
// iowrite16(0xff00,base);
iowrite16((ioread16(base)&0xff00)|0x00ff,base);
// iowrite16(0xff00,base + 0x08);
iowrite16((ioread16(base + 0x08)&0xff)|0xff00,base + 0x08);
return 0;
}
void led_exit(void)
{
unregister_chrdev(led_major,DEVICE_NAME);
device_destroy(led_class,MKDEV(led_major,0));
class_destroy(led_class);
iounmap(base);
release_mem_region(LED_CONTROLLER_BASE,LED_MEM_LEN);
}

module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("zhengxu");
MODULE_LICENSE("GPL");

...全文
1074 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
lihaoweiV 2011-11-06
  • 打赏
  • 举报
回复
请问楼主解决了问题了没, 如果解决了, 希望能共享一下答案。 拜托了
sy00800 2011-06-24
  • 打赏
  • 举报
回复
是不是你的ioremap的第二个参数不太对?
guolele2010 2011-03-08
  • 打赏
  • 举报
回复
你没有检测request_mem_region这函数返回值,它可能不能申请到那块内存空间,这样当然会失败
isolated_bb 2011-03-08
  • 打赏
  • 举报
回复
6楼说的是不是这个意思 直接对这个端口变量进行赋值从而达到对寄存器的访问???
我随便写了个例子
(*(volatile unsigned long *)S3C2410_GPBDAT) = 0xXX
这里的S3C2410_GPBDAT并不是你端口的实际地址吧(物理地址)??它需要有BSP(板级支持包)的支持,然后映射到虚拟地址区域的一个虚拟地址 所以它本质上应该还是个虚拟地址也就是0xc0000000以上的地址 虽然内核中没有对它进行ioremap的映射,是因为ARM体系结构是统一编制的??寄存器与内核地址空间本身就存在着固定地址的偏移??所以这样的操作也是对虚拟地址操作从而控制寄存器的状态!!
而我的目的是通过ioremap函数来映射到内核地址空间,然后修改虚拟地址空间达到控制寄存器的状态的目的,如果用BSP支持的话,我是可以正常访问的,但是如果没有BSP支持呢?我就是想实验下ioremap函数,不知确出现这么多的问题......
以上只属个人意见,不对之处,欢迎指出,本人虚心接受
isolated_bb 2011-03-08
  • 打赏
  • 举报
回复
呃....我明白你的意思了 但是直接对指针赋值的话 我看了很多参考文献 都说这样会很不好...一定要用标准的IO函数...并且应该不是 访问IO的问题 我再好好检查一下我的指针吧 也许不是ioremap的问题
steven_miao 2011-03-08
  • 打赏
  • 举报
回复
你说的意思我明白,我没有试过采用ioreab16这个来读取寄存器值,而是将ioremap后的指针直接使用的。如
base_addr= ioremap(xx,xx);
#define xx (*(volatile unsigned long *)(base_addr + 0x00))这样来用的。
然后赋值采用xx = 1;和temp=xx来实现寄存器的读写。不过应该还可以使用
struct regs
{
unsigned long reg1;
unsigned long reg2;
....
};
struct regs *regster;

register=(struct regs *)base_addr;
不过这个我没有试过,理论上是可以的,因为base_addr是内核虚拟地址。
steven_miao 2011-03-08
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 isolated_bb 的回复:]

6楼说的是不是这个意思 直接对这个端口变量进行赋值从而达到对寄存器的访问???
我随便写了个例子
(*(volatile unsigned long *)S3C2410_GPBDAT) = 0xXX
这里的S3C2410_GPBDAT并不是你端口的实际地址吧(物理地址)??它需要有BSP(板级支持包)的支持,然后映射到虚拟地址区域的一个虚拟地址 所以它本质上应该还是个虚拟地址也就是0xc0……
[/Quote]
S3C2410_GPBDAT就是ioremap返回的虚拟地址。
手机写程序 2011-03-08
  • 打赏
  • 举报
回复
if(!request_mem_region(LED_CONTROLLER_BASE,LED_MEM_LEN,"zx_led"))
{
printk("request_mem_region failed,pls check LED_CONTROLLER_BASE.\n");
return -1;
}
isolated_bb 2011-03-08
  • 打赏
  • 举报
回复
我在/proc/iomem下可以看到申请的端口 并且我也添加了打印信息 所以应该不是这个问题 但还是谢谢你的回答
isolated_bb 2011-03-07
  • 打赏
  • 举报
回复
首先 感谢大家回复!! (arm(2440)+linux)
我所粘贴的信息是我串口打印出来的全部的错误信息了,我也不知道具体的错误在哪里,但是只要注释掉ioremap就没有任何问题了(当然内存也无法映射了),因为编译的时候没有什么错误信息提示,加载内核模块的时候(insmod)也没有,只是查询模块挂载(lsmod)或者卸载模块的时候(rmmod)就会出现以上的错误信息
对于6楼的话我不是很理解,直接定义访问?那么访问的是I/O端口还是I/O内存?我认为你访问的是端口,I/O内存不是必须经过映射转化为虚拟地址才能访问么?ARM体系中不存在I/O端口吧?所以只要是寄存器的访问通通都要先映射?后访问虚拟内存空间??我程序的意思也是这样,先将寄存器的物理地址映射到虚拟内存空间,然后对虚拟内存空间进行访问,从而达到访问寄存器的目的!!!并且ioremap的返回地址也是对的(C4848050)是在3G以上的内核空间!!可是错误信息中提示"无法处理此时的请求页面调度的内核虚拟地址9f3008f7,这个是一个用户空间的地址",我是真不知道是怎么个情况了.....以上是个人理解 不知道对不对 还望请教 继续讨论
steven_miao 2011-03-07
  • 打赏
  • 举报
回复
是可以用ioremap去映射物理内存的,不过base的类型好像是 void __iomem *啊!还有啊,最好多用printk打印程序执行到哪儿出问题了,我一般直接用ioremap。
可以这样定义后就可以直接读值和写值,就把它当做一个变量就可以了。不过你也可以直接搞成结构体类型也成。
#define ADCCON (*(volatile unsigned long *)(base_addr + 0x00))
Wenxy1 2011-03-07
  • 打赏
  • 举报
回复
把错误多贴一点,感觉不是ioremap内存不能访问, ioremap用来映射IO的.
ezword 2011-03-07
  • 打赏
  • 举报
回复
使用gdb定位下,看看是哪句话出了问题。
isolated_bb 2011-03-07
  • 打赏
  • 举报
回复
unable to handle kernel paging request at virtual address 9f3008f7
pgd = c18b0000
[9f3008f7] *pgd = 00000000
INternal error : oops 5 [#1]


以上就是错误信息
isolated_bb 2011-03-07
  • 打赏
  • 举报
回复
unable to handle kernel paging request at virtual address 9f3008f7
pgd = c18b0000
[9f3008f7] *pgd = 00000000
INternal error : oops 5 [#1]
无知者无谓 2011-03-07
  • 打赏
  • 举报
回复
[Quote=引用楼主 isolated_bb 的回复:]
unable to handle kernel paging request at virtual address 7fXXXXXX
[/Quote]

信息太少
另[ code=C/C++ ]代码是复制到这的[ /code ]

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧