【发布时间】:2021-08-02 07:09:22
【问题描述】:
我在一个简单的 linux 驱动程序测试 (arm64) 中看到了一个奇怪的案例。
用户程序调用设备驱动程序的 ioctl 并将 uint64_t 的数组 'arg' 作为参数传递。顺便说一句,arg[2] 包含一个指向应用程序中变量的指针。下面是代码sn-p。
case SetRunParameters:
copy_from_user(args, (void __user *)arg, 8*3);
offs = args[2] % PAGE_SIZE;
down_read(¤t->mm->mmap_sem);
res = get_user_pages( (unsigned long)args[2], 1, 1, &pages, NULL);
if (res) {
kv_page_addr = kmap(pages);
kv_addr = ((unsigned long long int)(kv_page_addr)+offs);
args[2] = page_to_phys(pages) + offset; // args[2] changed to physical
}
else {
printk("get_user_pages failed!\n");
}
up_read(¤t->mm->mmap_sem);
*(vaddr + REG_IOCTL_ARG/4) = virt_to_phys(args); // from axpu_regs.h
printk("ldd:writing %x at %px\n",cmdx,vaddr + REG_IOCTL_CMD/4); // <== line 248. not ok w/o this printk line why?..
*(vaddr + REG_IOCTL_CMD/4) = cmdx; // this command is different from ioctl cmd!
put_page(pages); //page_cache_release(page);
break;
case ...
我在上面的代码中标记了第 248 行。如果我在此处注释掉 printk,则会发生陷阱并且虚拟机崩溃(我在 qemu 虚拟机上执行此操作)。 cmdx 是根据应用程序的 ioctl 命令设置的整数值,vaddr 是设备的虚拟地址(从 ioremap 获取)。如果我保留 printk,它会按我的预期工作。什么情况下可以做到这一点? (缓存还是 tlb?)
【问题讨论】:
-
您能否发布崩溃报告?如果它报告了什么
-
因为虚拟机本身崩溃了,我在VM上看不到内核的报告。我只看到这个:./runit20a: line 10: 16669 Segmentation fault (core dumped) qemu-system-aarch64 -nographic -machine ab21q,gic-version=max,iommu=smmuv3 -m 1G -cpu max -smp 4 -netdev user,id=vnet,hostfwd=:127.0.0.1:0-:22 -device virtio-net-pci,netdev=vnet -drive file=ab21q-ubuntu-20.04-image.img,if=none,id=drive0, cache=writeback -device virtio-blk,drive=drive0,bootindex=0 -drive file=ubuntu-20.04-mini.iso,if=none,id=drive1,cache=writeback
-
-device virtio-blk,drive=drive1,bootindex=1 -drive file=flash0.img,format=raw,if=pflash -drive file=flash1.img,format=raw,if=快闪。但这是来自 qemu 崩溃。
-
有时没有 printk 语句,它不会崩溃,但来自用户域的值不会改变(设备应该会改变值)。当它没问题时(使用 printk),该值已被设备(qemu 模型)更改。
-
我猜
printk调用是一个障碍。您应该使用writel来写入寄存器。
标签: linux-kernel linux-device-driver arm64