Tag: linux kernel

什么是相当于memset函数的Linux内核?

我正在编写一个驱动程序,要求我清除分配给零的所有内存。 memset是一个用户空间函数,但我想知道内核是否提供了一个可以帮助我做到这一点的宏。

kernel.h中min宏中“(void)(&_min1 ==&_min2)”的function是什么?

在kernel.h中, min定义为: #define min(x, y) ({ \ typeof(x) _min1 = (x); \ typeof(y) _min2 = (y); \ (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) 我不明白行(void) (&_min1 == &_min2); 确实。 是某种类型检查还是什么?

函数声明不是C中的原型

我正在学习为初学者编写Linux内核模块。 我要做的是使用DFS算法将每个任务及其子进程写入内核日志。 但是当我使用Makefile编译代码时,它显示上面的错误: function declaration isn’t a prototype [-Werror=strict-prototypes] struct task_struct *current; 它在函数DFS中指出task_struct关键字。 这是我的代码: # include # include # include # include # include void DFS (struct task_struct *task) { struct task_struct *current; struct list_head *list; list_for_each (list, &task->children) { current = list_entry(list, struct task_struct, sibling); printk(KERN_INFO “%d\t%d\t%s \n”, (int)current->state, current->pid, current->comm); if (current != […]

自旋锁初始化函数

要在内核v4.19-rc5中初始化自旋锁,必须使用如下定义的spin_lock_init宏: #define spin_lock_init(_lock) \ do { \ spinlock_check(_lock); \ raw_spin_lock_init(&(_lock)->rlock); \ } while (0) 函数spinlock_check(_lock)只返回&lock->rlock 。 本文解释说: spinlock_check的实现非常简单,这个函数只返回给定自旋锁的raw_spinlock_t,以确保我们得到完全正常的原始自旋锁 我不明白这个函数是如何执行检查的 。 我期待ckeck函数中的一些if语句。 对不起,我是内核编程的新手。

奇怪的错误(取消引用指向不完整类型的指针)

void get_cwd(char* buf) { char *result; current->fs->pwd; result = get_dentry_path(current->fs->pwd); memcpy(buf, result, strlen(result)+1); kfree(result); } 错误:取消引用指向不完整类型的指针 错误指向current-> fs-> pwd; 包括: #include #include #include #include #include #include #include #include #include #include #include 如果我键入current-> fs; 在第5行gcc不会在这一行给出错误。 问题在于pwd字段。

如何使用页面error handling程序映射页面?

我想使用struct vm_area_struct *的pagefault处理程序将物理页面映射到用户空间。 以下是我的进展方式: 我在模块初始化期间使用alloc_page(GFP_USER)全局分配页面(我尝试了各种GFP)。 我创建了一个struct vm_area_struct ,设置了一个自定义的vma处理程序,并将vma附加到current->mm 。 发生页面错误时: 我将vmf->page设置为我之前分配的页面并返回0。 结果是,在页面错误之后, vma中的每个虚拟页面都应映射到同一物理页面。 但这是我注意到的: 当我从内核模块写入页面时,它反映在我的用户空间程序中。 当我从用户空间写入页面时,我没有从内核模块中看到它。 当我在我的内核模块中使用get_user_pages来获取页面(而不是使用我的全局变量)时,我得到的物理地址与全局页面变量不同。 我使用page_to_phys(page)打印地址。 写入此页面会反映在我的用户空间程序中。 所有这些都是在页面error handling程序中完成的。 如何解释这种奇怪的行为? 要从内核空间访问页面,我使用的是kmap_atomic和kunmap_atomic 。

使用Netfilter封装和解封装IPv4数据包

我在netfilter框架中有两个钩子。 一个在NF_IP_PRE_ROUTING用于传入数据包,另一个在NF_IP_LOCAL_OUT用于传出数据包。 传出包: 现在,从特定IP地址发出的所有IPv4数据包都封装在另一个IPv4-UDP数据包中。 我使用pskb_expand_head API为封装提供了更多的空间。 然后,用ip_route_output_key找到合适的rtable 。 使用rtable ,我重新分配skb->dst和skb->dev 。 然后,我继续使用NF_ACCEPT接受数据包。 skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); skb->dev = skb_dst(skb)->dev; 传入数据包: 现在,接收所有Encapsulated Packets并根据端口号识别。 并且,拉出封装(IP+UDP+XYZ HEADER) 。 和传出数据包类似,我使用ip_route_output_key来获取rt(rtable)。 使用rtable重新分配skb->dst和skb->dev 。 然后我接受带有NF_ACCEPT的数据包 所以,碰巧我也收到了defrags传入的数据包,我有点混乱他们应该如何处理。 我希望碎片整理数据包排队,然后接收整个数据包。 任何想法。 我一直在经历可用的function ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER); 但这似乎是用于在NF_IP_LOCAL_IN阶段组装数据包,但我希望在NF_IP_PRE_ROUING阶段组装数据包。 任何有关这方面的帮助将不胜感激。

禁用缓存后系统变得非常慢

我通过为我的intel机器设置CR0的CD位来禁用缓存。 我使用了上一篇文章中描述的代码 我还使用smp_call_function()函数来设置所有CPU的CR0。 问题是: 设置所有CPU的CR0的CD位后,机器变得非常慢。 我甚至不能使用键盘。 我的问题是: 我想通过设置CR0的CD位来禁用缓存后检查CR0寄存器。 所以我至少需要能够使用键盘。 无论如何,我禁用缓存后可以帮助我使用键盘吗? 完全出乎我的意料,禁用缓存会使系统几乎冻结。

在内核驱动程序中顺序访问大页面

我正在使用一个使用由大页面支持的缓冲区的驱动程序,我发现大页面的后续性存在一些问题。 在用户空间中,程序使用mmap系统调用分配由largepages支持的大缓冲区。 然后通过ioctl调用将缓冲区传送给驱动程序。 驱动程序使用get_user_pages函数来获取该缓冲区的内存地址。 这适用于1 GB的缓冲区大小(1个巨页)。 get_user_pages返回了很多页面( HUGE_PAGE_SIZE / PAGE_SIZE ),但它们都是HUGE_PAGE_SIZE / PAGE_SIZE ,所以没有问题。 我只是使用page_address获取第一页的地址并使用它。 当另一个程序在char设备上执行mmap调用时,驱动程序还可以使用remap_pfn_range将该缓冲区映射回用户空间。 但是,当缓冲区由多个巨页支持时,事情会变得复杂。 似乎内核可以返回由非连续的大页面支持的缓冲区。 即,如果巨页页面的布局是这样的 +——+——+——+——+ | HP 1 | HP 2 | HP 3 | HP 4 | +——+——+——+——+ ,通过保留HP1和HP4,或HP3,然后HP2,可以满足对大页面支持的缓冲区的请求。 这意味着当我在最后一种情况下使用get_user_pages获取页面时,页面0的地址实际上是在页面262.144(下一个巨页的头部)的地址之后的1 GB。 有没有办法隔离访问这些页面? 我尝试重新排序地址以找到较低的地址,这样我就可以使用整个缓冲区(例如,如果内核给我一个由HP3支持的缓冲区,HP2我用作HP2的基地址),但它似乎会扰乱数据在用户空间中(该重新排序的缓冲区中的偏移量0可能在用户空间缓冲区中偏移1GB)。 TL; DR:给定> 1个无序的大页面,有没有办法在Linux内核驱动程序中按顺序访问它们? 顺便说一句,我正在使用3.8.0-29通用内核的Linux机器。

内核空间中PCI内存的地址映射

我正在尝试从可加载的内核模块读取和写入PCI设备。 因此我按照这篇文章 : pci_enable_device(dev); pci_request_regions(dev, “expdev”); bar1 = pci_iomap(dev, 1, 0); // void iowrite32(u32 val, void __iomem *addr) iowrite32( 0xaaaaaaaa, bar1 + 0x060000); /* offset from device spec */ 但最终设备没有按预期完成他的工作。 然后我查看bar1后面的地址,发现了一个非常大的值ffffbaaaaa004500 。 在这一点上,我真的不明白那里发生了什么,什么是正确的。 我可以将bar1解释为内核地址空间内的地址,该地址直接指向基本地址,该地址是PCI芯片选择地址的0x60000偏移量吗? 如何将写入bar1 + offset的值复制到设备中? 该机制如何在iowrite32和pci_iomap后面工作? 感谢致敬 亚历克斯 PS:我成功测试了同一地址的回读。 注册PCI设备的说明: PCIBAR0 PCI基地址0; 用于存储器映射配置寄存器 PCIBAR1 PCI基地址1; 用于I / O映射配置寄存器 PCIBAR2 PCI基地址2; 用于本地地址空间0 PCIBAR3 PCI基地址3; […]