把部分内存设置成uncacheable

整体思路:找到想要设成uncacheable的内存地址,然后通过set_memory_uc()这个函数把这个地址所在的page设成uncacheable; 这些操作在一个内核模块中完成。

下面通过两个例子进行说明,一个例子是把GDT和IDT所在的page设成uncacheable; 另一个例子是把apic_timer_interrupt()中段函数所在的page设成uncacheable。

例子1——把GDT和IDT所在的page设成uncacheable:

  1. 新建一个文件夹setPageUncacheable, 然后建两个文件setPageUncacheable.cMakefile:

    mkdir setPageUncacheable
    cd setPageUncacheable
    touch setPageUncacheable.c
    touch Makefile
    
  2. setPageUncacheable.c里面写入以下内容:

    #include <linux/init.h>
    #include <asm/apic.h>
    #include <asm/set_memory.h>
    #include <linux/module.h>
    /* Needed by all modules */
    #include <linux/kernel.h>
    
    struct desc_ptr1{
    	unsigned short size;
    	unsigned long address;
    } __attribute__((packed));
    
    static inline void store_gdt(struct desc_ptr1 *ptr){
    	asm("sidt %w0":"=m" (*ptr));  //sgdt
    }
    
    static int __init test_init(void)
    {
    	printk("-------- test start ---------");
    
    	//get idtr adress
    	unsigned long addr;
    	int pages,retval;
    	struct desc_ptr1 idt_descr1;
    	store_gdt(&idt_descr1);
    	printk("idtr address:%#lx 			size:%d\n",idt_descr1.address,idt_descr1.size);
    
    	//set idt page as uncacheable
    	addr = idt_descr1.address;
    	// addr = (unsigned long)0xffffffff9c602800; //ffffffff9c602800
    	pages = 1;
    	retval = set_memory_uc(addr, pages);
    	if (retval) {
    		printk("set_memory_uc failed.Error\n");
    		return retval;
    	}
    	printk("set memory_uc success\n");
    	printk("---------------------------");
    	return 0;
    }
    static void __exit test_exit(void)
    {
    	printk("-------- test over ----------");
    	return;
    }
    MODULE_LICENSE("GPL");
    module_init(test_init);
    module_exit(test_exit);
    

    (所有代码的功能大致分成两个部分,第一部分是从idtr寄存器取出地址,第二部分是通过set_memory_uc()设置相应page)

  3. Makefile里面写入以下内容:

    obj-m += setPageUncacheable.o
    all:
    	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    clean:
    	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
    
  4. 在刚刚的目录下,通过make生成内核模块, 并加载该内核模块:

    cd setPageUncacheable
    make
    sudo insmod ./setPageUncacheable.ko
    
  5. 加载完后可通过查看/var/log/syslog确认是否加载成功:

    tail -f /var/log/syslog
    

    成功的话,会看到类似下面的输出:
    在这里插入图片描述

  6. 成功设置后,卸载模块:

    sudo rmmod setPageUncacheable
    
  7. 刚刚的操作只是把idt所在的page设成了uncacheable, 如果要进一步设置gdt所在的table, 需先把setPageUncacheable.c里面的sidt改成sgdt,然后再重复步骤4-6就好了。

例子2——把apic_timer_interrupt()中段函数所在的page设成uncacheable

  1. 函数apic_timer_interrupt()的地址可以通过查看文件/proc/kallsyms知道,查看该文件一定要用root权限,不然看到的地址都是0x0:
    sudo vim /proc/kallsyms
    
    打开文件后找到apic_timer_interrupt()对应的地址,比如下图中apic_timer_interrupt()对应的地址就是0xffffffffb4001d20
    在这里插入图片描述
  2. 把找到的地址赋值给setPageUncacheable.c里面pages = 1;上一行的addr字段。 然后重复例子1中的步骤4-6。
  3. 完。

进一步验证

进一步验证是否设置成功,可通过加载内核模块dump_pagetables.ko,然后在sysfs里面查看所有page对应的属性flag,U对应uncacheable。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值