我正在尝试编写Linux内核模块。在那里,我已经注册了开放,读,写,释放功能,如下所示:
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
驱动程序将字符设备创建为/ dev / hvacchar。这部分似乎工作正常。
为了测试,我写信给驱动程序:
cat > /dev/hvacchar
asdf1234
呼叫过程立即被杀死。
我已从dev_write中删除了所有内容,只剩下一个printk()。这是代码:
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
printk(KERN_INFO "HVACCHAR: Entered dev_write()\n");
printk(KERN_INFO "HVACChar: b4 sprintf(): buffer=%c\n", buffer[0]);
return len;
}
tail -f /var/log/kern.log显示第一个printk语句,但不显示第二个。我猜它在尝试访问缓冲区变量时崩溃了。根据我的理解,它由系统提供,它应该有一个有效的内存分配。我做错了什么?
这是来自kern.log的整个转储
Aug 31 15:17:28 app-ThinkCentre-M900 kernel: [873016.888579] HVACChar: Device has been opened 1 time(s)
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.627170] HVACCHAR: Entered dev_write()
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.627203] BUG: unable to handle kernel paging request at 00000000015c9004
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.630465] IP: [<ffffffffc08f7070>] dev_write+0x20/0x40 [hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.633714] PGD 51364067 PUD 374d3067 PMD 374f6067 PTE 80000000ac7de867
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.637075] Oops: 0001 [#36] SMP
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.640346] Modules linked in: hvacchar(OE) binfmt_misc btrfs xor raid6_pq ufs qnx4 hfsplus hfs minix ntfs msdos jfs xfs libcrc32c uas usb_storage ebbchar(OE) rfcomm bnep intel_rapl x86_pkg_temp_thermal input_leds intel_powerclamp coretemp snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec i915_bpo snd_hda_core snd_hwdep snd_pcm kvm_intel snd_seq_midi kvm snd_seq_midi_event snd_rawmidi snd_seq hci_uart irqbypass btbcm btqca snd_seq_device btintel snd_timer crct10dif_pclmul intel_ips drm_kms_helper bluetooth drm crc32_pclmul ghash_clmulni_intel aesni_intel snd aes_x86_64 lrw gf128mul mei_me glue_helper ablk_helper serio_raw cryptd i2c_algo_bit fb_sys_fops syscopyarea sysfillrect sysimgblt soundcore mei video acpi_pad 8250_fintek wmi intel_lpss_acpi intel_lpss pinctrl_sunrisepoint pinctrl_intel acpi_als kfifo_buf i2c_hid industrialio mac_hid parport_pc ppdev lp parport hid_generic usbhid hid e1000e psmouse ptp ahci pps_core libahci fjes [last unloaded: hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.660535] CPU: 1 PID: 31522 Comm: cat Tainted: G D OE 4.4.0-92-generic #115~14.04.1-Ubuntu
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.662854] Hardware name: LENOVO 10FLS13501/30D0, BIOS FWKT5AA 09/23/2016
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.664735] task: ffff88010759e900 ti: ffff8800374e0000 task.ti: ffff8800374e0000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.666473] RIP: 0010:[<ffffffffc08f7070>] [<ffffffffc08f7070>] dev_write+0x20/0x40 [hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.668233] RSP: 0018:ffff8800374e3ea8 EFLAGS: 00010282
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.669703] RAX: 000000000000001d RBX: 00000000015c9000 RCX: 0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.671127] RDX: 0000000000000001 RSI: ffff88023dc8dd98 RDI: ffff88023dc8dd98
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.672547] RBP: ffff8800374e3eb8 R08: 000000000000000a R09: 0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.673890] R10: 0000000000000000 R11: 00000000000009bc R12: 0000000000000009
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.675080] R13: 0000000000000009 R14: ffff8800374e3f20 R15: 0000000000000009
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.676237] FS: 00007f92c016d740(0000) GS:ffff88023dc80000(0000) knlGS:0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.677373] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.678484] CR2: 00000000015c9004 CR3: 000000008fbd5000 CR4: 00000000003406e0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.679420] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.680331] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.681209] Stack:
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.682065] ffff880139bf6300 00000000015c9000 ffff8800374e3ec8 ffffffff812010c8
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.682936] ffff8800374e3f08 ffffffff812016e2 ffffffff8120161c ffff880139bf6300
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.683789] ffff880139bf6300 00000000015c9000 0000000000000009 0000000000000009
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.684640] Call Trace:
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.685436] [<ffffffff812010c8>] __vfs_write+0x18/0x40
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.686232] [<ffffffff812016e2>] vfs_write+0xa2/0x1a0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.687028] [<ffffffff8120161c>] ? vfs_read+0x10c/0x130
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.687818] [<ffffffff81202406>] SyS_write+0x46/0xa0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.688604] [<ffffffff8180cd36>] entry_SYSCALL_64_fastpath+0x16/0x75
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.689391] Code: c0 31 c0 5d c3 66 0f 1f 44 00 00 0f 1f 44 00 00 55 48 c7 c7 80 80 8f c0 31 c0 48 89 e5 41 54 49 89 d4 53 48 89 f3 e8 ff cb 88 c0 <0f> be 53 04 0f be 33 48 c7 c7 a8 80 8f c0 31 c0 e8 ea cb 88 c0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.691080] RIP [<ffffffffc08f7070>] dev_write+0x20/0x40 [hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.691905] RSP <ffff8800374e3ea8>
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.692728] CR2: 00000000015c9004
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.693552] ---[ end trace eee0478c7200f93f ]---
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.693962] HVACChar: Device successfully closed
我是linux和设备驱动程序的新手。请温柔:)
答案 0 :(得分:2)
嗯,原因很简单。您的代码在内核上下文中执行,而包含数据的缓冲区来自用户空间。任何内核的最大目标之一是提供内存保护,因此内核和用户空间使用不同的内存区域。如果需要从用户空间获取一些数据,请使用 copy_from_user() 功能将其复制到内核内存中。如果您不遵循该方案并且只是尝试直接访问数据,这将导致内存访问冲突,并且内核会抱怨它(就像在您的日志输出中):&#34;无法处理内核分页请求&#34;。
因此,正确的解决方案(基于您的代码)看起来有点像这样:
#include <linux/slab.h>
static ssize_t dev_write(struct file *filep, const char __user *buffer, size_t len, loff_t *offset) {
char *buf_internal;
buf_internal = kmalloc(len, GFP_KERNEL);
if (buf_internal == NULL)
return -ENOMEM;
if (copy_from_user(buf_internal, buffer, len)) {
kfree(buf_internal);
return -EFAULT;
}
buf_internal[len - 1] = '\0';
printk(KERN_INFO "HVACCHAR: Entered dev_write()\n");
printk(KERN_INFO "HVACChar: b4 sprintf(): buffer=%c\n", buf_internal[0]);
kfree(buf_internal);
return len;
}
请找到添加到函数原型的__user限定符,以突出显示缓冲区的性质。我没有测试代码,但我希望这个想法非常明确:)