Linux内核相关信息杂谈笔记
1.x86的一种方式修改内核内存读写属性cr0方式
当自己编写对应的驱动,要将驱动数据写入内核使用,需要驱动文件ko文件中编写关闭跟打开内核内存的相关函数,通常x86架构的通过如下汇编修改cr0属性即可。如下:
// 关闭当前x86内核属性保护
unsigned int get_cr0(void)
{
unsigned int cr0 = 0;
unsigned int ret;
asm volatile ("movq %%cr0, %%rax": "=a"(cr0));
ret = cr0;
// clear the 20th bit of CR0
cr0 &= 0xfffeffff;
asm volatile ("movq %%rax, %%cr0"::"a"(cr0));
return ret;
}
//重新打开x86内核属性保护
void set_cr0(unsigned int val)
{
asm volatile ("movq %%rax, %%cr0": : "a"(val));
}
//系统函数设置
void funcr0()
{
write_cr0(read_cr0() & (~0x10000));
//doing
write_cr0(read_cr0() | (0x10000));
}
2.符号表信息的获取以及通过符号表调用实现修改内存的cr0读写属性修改
符号表是一种系统调用的列表,系统内核存储在一个数组当中。sys_call_table_ptr,当通过系统内部的数组标识,可以获取到对应内核方法。
a.通过从/proc/kallsyms符号表中读取对应的符号表信息,找到名称为 “sys_call_table”符号表对应的地址,可通过该符号表收地址,通过具体的类型的类型索引找到对应的回调函数,当有事件触发时,调用对应的回调函数。
例如:
// 通过读取上文件:
unsigned long* pSyscallAddr = NULL;
char* p = NULL;
while (p = fgets(buf, sizeof(buf), fileallsyms)) {
if (strstr(buf, " sys_call_table")) {
sscanf(buf, "%lx", pSyscallAddr);
break;
}
}
b.或者/boot/System.map-内核版本号,相关文件获取对应的符号表地址。
struct utsname fileName; //获取name -r信息
char szFileName[256];
strcpy(szFileName, "/boot/System.map-");
uname(&fileName);
strcat(szFileName, fileName.release);
if(F_OK == access(szFileName, R_OK)){
return fopen(szFileName, "r");
}
c.arm架构关闭系统内存读写属性
void (*updte_mapping_prot)(phys_addr_t phys,unsigned long virtphys_addr_t size pgprot_t prot);
static unsigned long start_ro,end_ro,section_size;
void initMapping()
{
updte_mapping_prot = (void*)kallsyms_lookup_name("update_mapping_prot");
start_ro = (unsigned long)kallsyms_lookup_name("__start_rodata")
end_ro = (unsigned long)kallsyms_lookup_name("__end_rodata")
section_size = end_ro - start_ro;
}
//cr0系统内核的读写属性
void close_cr0()
{
update_mapping_prot(__pa_symbol(start_ro),(unsigned long)start_ro,section_size,PAGE_KERNEL);
}
void open_cr0()
{
update_mapping_prot(__pa_symbol(start_ro),(unsigned long)start_ro,section_size,PAGE_KERNEL_R0);
}
3.Linux内核相关属性杂谈笔记
3.1 linux内核中current结构体
current
是一个指向当前运行进程(或者说任务)的指针。它是 task_struct
结构体的一个实例,而 task_struct
结构体用于表示进程或任务的描述信息。current
变量是一个宏,其定义通常是通过一个内联汇编实现的。
以下是 current
在内核源代码中的定义:
#include <linux/sched.h>
#define current (current_thread_info()->task)
这里,current_thread_info()
用于获取当前线程信息的指针,而 task
是 task_struct
结构体中的一个成员,表示指向进程描述信息的指针。
task_struct
结构体包含了关于进程的大量信息,如进程状态、进程 ID、进程的地址空间信息、调度信息等。current
通过指向当前运行进程的 task_struct
结构体,提供了对当前进程各种属性的访问。
在内核代码中,可以通过 current
来访问当前运行进程的信息,例如:
pid_t current_pid = current->pid; // 获取当前进程的进程ID
需要注意的是,由于 current
在全局范围内使用,它只能在进程上下文中(而非中断上下文)使用。在中断上下文中,可以使用 get_current()
函数获取当前运行的任务指针。
#include <linux/sched.h>
struct task_struct *task = get_current();
总的来说,current
提供了一种方便的方式来访问当前运行进程的信息,但在使用时需要小心,确保在适当的上下文中使用。
注:其中两个变量常使用:
? ? ? ? ?current->comm :进程名称。?current->pid:进程id
3.2 内核中GFP_KERNEL定义
在 Linux 内核中,GFP_KERNEL
是一个用于内存分配的标志位。它表示内核正在以进程的上下文(即在进程上下文中运行的代码)中进行内存分配。这是一种常见的内存分配标志,用于表示分配是在内核代码执行期间进行的,因此可能需要使用进程上下文可用的资源。
GFP
代表 "Get Free Pages",而 KERNEL
表示在内核上下文中进行分配。这种标志通常用于在内核模块、驱动程序或其他运行在内核空间的代码中进行内存分配。
例如,在使用 kmalloc
函数进行内存分配时,可以使用 GFP_KERNEL
标志:
#include <linux/slab.h> void* ptr = kmalloc(size, GFP_KERNEL);
这表示 kmalloc
将在内核上下文中尝试分配内存,并且在分配失败时可能会睡眠等待内存可用。与之相对的是 GFP_ATOMIC
,表示在不睡眠的情况下进行内存分配,通常用于中断处理程序等不能休眠的上下文。
这些标志提供了有关内存分配行为的信息,以确保分配的内存满足特定上下文的要求。
3.3 内核中的DEFINE_RWLOCK宏定义
?DEFINE_RWLOCK
是一个用于定义读写锁(rwlock)的宏。读写锁是一种特殊的锁机制,允许多个读者同时访问共享资源,但只允许一个写者访问。这有助于提高并发性能,因为多个线程可以同时读取数据,但写操作需要独占性。例如:
#include <linux/rwlock.h>
DEFINE_RWLOCK(my_rwlock);
void example_function(void) {
// 读者加锁
read_lock(&my_rwlock);
// 执行读操作
// 读者解锁
read_unlock(&my_rwlock);
// 写者加锁
write_lock(&my_rwlock);
// 执行写操作
// 写者解锁
write_unlock(&my_rwlock);
}
代码中,DEFINE_RWLOCK(my_rwlock)
定义了一个名为 my_rwlock
的读写锁,并在 example_function
中展示了如何使用这个读写锁。读者使用 read_lock
和 read_unlock
加锁和解锁,而写者使用 write_lock
和 write_unlock
。
在实际的内核代码中,读写锁常用于保护对共享数据结构的并发访问。通过使用读写锁,内核可以实现高效的读取和适当的写入同步。需要注意的是,读写锁的正确使用需要开发人员仔细考虑并发访问的模式,以防止潜在的竞态条件和死锁。
? ? ? ?
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!