2013-05-16 78 views
1

我正在制作一个FPGA片上系统系统,在该系统中我使用内核模块在运行时更改了硬件配置。他们的系统使用Linux 2.6和LEON3 CPU(SPARC)。有些位文件工作正常,但对于某些位文件,我收到“内核非法指令”或“无法在虚拟地址x处理内核分页请求”。我很肯定我的硬件是正确的,因为我已经用另一种方法测试了它,并且我改变的硬件与CPU无关。我猜这是一个软件/内核模块错误。这发生在我第14次进入内核模块的写入方法之后。我不知道从哪里开始进行调试。任何帮助,将不胜感激。写入内核模块时发生内核非法指令

# cat x > /dev/y 
Unable to handle kernel paging request at virtual address 00001000 
tsk->{mm,active_mm}->context = 00000045 
tsk->{mm,active_mm}->pgd = fc013400 
       \|/ ____ \|/ 
       "@'/ ,. \`@" 
       /_| \__/ |_\ 
       \__U_/ 
cat(86): Oops [#1] 
PSR: f30000c7 PC: f0089e90 NPC: f0089e94 Y: 00000000 Not tainted 
PC: <vfs_write+0xb8/0x148> 
%G: 80080000 00001000 00000001 fd000100 00000dae f09c4370 fbca0000 0000fffb 
%O: 00001000 00000003 00001000 fe60e5dc fe60e430 fe60e420 fbca1e80 f0089e80 
RPC: <vfs_write+0xa8/0x148> 
%L: fbdcad40 00000000 fbca1e78 00000004 fbc0e940 00000000 fbdd2000 f0035784 
%I: 00001000 efe07b50 00001000 fbca1f40 00000000 00000000 000007af 000007af 
Disabling lock debugging due to kernel taint 
Caller[000007af]: 0x7af 
Instruction DUMP: d204200c f602600c c416e072 <84088001> 03000010 80a08001 02 
800018 b2102002 c404201c 
Killed 
# 

内核模块写入方法:

ssize_t icap_write(struct file *filp, char *buf, size_t count, loff_t *f_pos) { 
unsigned long words, data, *pdata, mem_loc_temp; 

pdata = (unsigned long *)buf; 
mem_loc_temp = icap_mem_loc;//reset mem_loc_temp 

while((pdata < (buf + count)) && (mem_loc_temp < icap_mem_loc+4096)){ 
     leon_store_reg(mem_loc_temp,*pdata); 
     pdata++; 
     mem_loc_temp+=4; 
    } 
} 

我觉得这是我的问题。 pdata正在走出界限。它是一个可行的修复到其修改为: --------------更新的代码-------------

unsigned long *pdata; 
static int __init icap_init(void) { 
... 
pdata = (unsigned long *)kmalloc(mem_size*sizeof(char), GFP_KERNEL); 
... 
} 

ssize_t icap_write(struct file *filp, const char *buf, 
        size_t count, loff_t *f_pos) { 

int i, cycles, spins; 
ssize_t result; 

if(count%4 != 0){ 
    printk(KERN_INFO "ERROR: count = %d is not a multiple of 4. count mod 4 = %u\n Assuming 0 padding for last word. Configuration may not have completed as expected.",count, count%4); 
    //return count; 
} 

result = copy_from_user(pdata, buf, count); 
if (result) { 
    printk(KERN_INFO "copy_from_user failed, returned: %d\n.", result); 
    return -EINVAL; 
} 
spins = 0; 
while((leon_load_reg(ctrl_mem_loc+8) & 0x10) == 0){//check done 
    spins++;//spin on NOT done 
} 
if (spins > 0) 
    printk(KERN_INFO "%d spins\n", spins); 

leon_store_reg(ctrl_mem_loc+8, 0);//deassert start 

if(count == 4096){ 
    cycles=min((unsigned long)1024, (unsigned long)mem_size/4); 
}else if((count > 0) && (count < 4096)){ 
    cycles=min(((unsigned long)count+3)/4, (unsigned long)mem_size/4); 
}else{ 
    printk(KERN_INFO "ERROR: count > 4096\n"); 
    cycles = 0; 
} 

for(i = 0; i < cycles; i++){ 
    leon_store_reg(icap_mem_loc+4*i, pdata[i]); 
} 

leon_store_reg(ctrl_mem_loc, cycles);//set number of samples 
leon_store_reg(ctrl_mem_loc+8, 0x1);//set start high 

return count; 
} 
+0

你确定你的修补程序有效吗?因为它看起来和我原来的一样 - 写-1条目,然后写最后一条... –

+0

增加了更多的代码来使它更清晰。我的内存空间是4096个字节,我希望buf有4096个字节,数量是4096.也许我现在应该对它进行硬编码以避免混淆,因为这不会被重用或任何其他内容。 – Stuart

+0

“4K”是一个内核页面。你不是想用'copy_from_user'。 –

回答

1

你可能需要在这里放置一些代码,以便我们更好地帮助您。

我的第一个猜测是你在你的代码中有一个数组覆盖你的代码,当你打到第14个条目时,它碰到系统需要的东西并导致异常。如果可能的话,在程序写出来的时候跟踪它,看它是否在写它应该在的地方。不同的文件将在内存中的不同位置,如果这些区域不是系统关键的,它可能会解释为什么它们不会崩溃,并且这是一个问题。从您的崩溃转储

一件有趣的事:

Unable to handle kernel paging request at virtual address 00001000

即4096十进制 - 一样while循环偏移。所以也许有一些事情在那里发生,但是你的代码似乎并没有解决它,并且可能会让情况变得更糟,因为在while循环中有两个条件要注意。

更新为你的代码改变

铸造pdataunsigned long *如果基指针不long对齐可能不是安全的。不知道你的系统是否允许未对齐的内存访问,所以要小心。

icap_mem_loc是一个未知类型,但似乎是一个整数值?如果是这样,那么处理积分值和指针就是在寻求未来的麻烦。

您正在比较无符号长指针和while循环中的无符号字符指针 - 可能是安全的,但要小心指针算术。

您是否在编译此代码时启用了警告?如果没有,那么这样做,因为我敢肯定它会大喊上述问题......

如果icap_mem_loc为NULL或0,会发生什么情况?如果这是一个错误条件,你需要处理它 - 你的页面请求有点意味着这是一个糟糕的条件,你没有任何ASSERT或条件来处理这个。

最后,mem_loc_temp+=4;4 - 你确定long4字节大小在您的系统上。应该是sizeof()'d或更好,而不是消除歧义。

不是试图在这里攻击你,而是指出我看到的每一个潜在的失败点,以便我们能够为你解决这个问题。

+0

我修改了这个问题。我想我发现了这个问题,但是会很感激反馈。 – Stuart

+0

以上评论 - 不要以为是... –

+0

不用担心,我真的很感谢帮助。我现在摆脱了大部分警告。我很确定系统不允许未对齐的访问。 'icap_mem_loc'是一个int并且静态设置。我通过将'buf + count'转换为'unsigned long'来修复'buf + count',在初始化方法中检查大小。 – Stuart