微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在内核模块中分配物理上连续的页面

如何解决在内核模块中分配物理上连续的页面

我正在尝试使用 alloc_pages_exact 函数在 DRAM 中分配物理上连续的页面。当我尝试分配 10MB 的页面时,返回的地址始终为 0。但是当我尝试分配 1MB 的页面时,分配几乎是立即的。另外,有人可以告诉我如何找到DRAM的确切行大小吗?我不得不搜索我的 RAM 的数据表才能弄清楚。我想知道是否有一个命令可以确定 DRAM 的行大小。早些时候我认为系统页面大小也应该是 DRAM 行大小,但结果系统页面大小是 4kB,而我计算出的行大小变成了 8kB。请帮忙。 代码

static int __init hello_entry(void){

    unsigned long i = 0;
    unsigned long j = 0;
    unsigned long counter;
    int fault = 0;
    char default_value = 0xff;
    
    
    unsigned long size_of_memory_to_test_bytes = 10 * 1024 * 1024;//10MB chunk
    unsigned long page_size = 8 * 1024;//8kB page size. From data sheet for elpida 4GB ddr3 ram
    unsigned long number_of_pages = size_of_memory_to_test_bytes / page_size;
    unsigned long number_of_hammer_access = 200000;
    
    printk("Number Of Bytes to allocate: %ld\n",number_of_pages * page_size);
    char* pages = (char *)alloc_pages_exact(number_of_pages * page_size,GFP_KERNEL);
    
    while(pages == 0);//The Program must wait till enough pages have been allocated!
    
    printk("Starting Address: %x",pages);

    char *hammerRow0,*hammerRow1,*victimRow;
    
    char hammerRow0_data,victimRow_data,hammerRow1_data,read_midvalue;

    printk(KERN_ALERT "Memory Test Entry!\n");

    printk(KERN_ALERT "Page Size: %ld\n",page_size);
    printk(KERN_ALERT "Cache Line Size: %d\n",cache_line_size());



    //The design consists of two hammer rows which will be repeatedly accessed one after another
    //There will be a victim row in between the two hammer rows,kind of like a victim row sandwiched between two hammer rows
    //This will server two purposes:
    //1. Greater probability of inducing bitflip in the victim row due to repeated access of two adjacent rows.
    //2. Clearing out the row buffer of DRAM chip so that it is guaranteed that the wordline will be accessed to access the data
    printk(KERN_INFO "Rowhammer Test Starts\n");
    for(counter = 0; counter < number_of_pages - 2; counter++){
        //Doing the rowhammer test on every page of dram
        hammerRow0 = pages + counter;
        victimRow = hammerRow0 + page_size;
        hammerRow1 = victimRow + page_size;

        //Storing initial data into rows to check them later for errors
        for(i = 0; i < page_size / sizeof(char); i++){
            //Setting all bits of dram 1 to maximize the possibility of charge leak
            hammerRow0[i] = default_value;
            victimRow[i] = default_value;
            hammerRow1[i] = default_value;
        }


        //Starting Hammer Test
        //printk(KERN_INFO "Rowhammer Test Starts\n");
        fault = 0;

        for(j = 0; j < number_of_hammer_access; j++){
        
            //hammerRow0 access
            
            //This is an x86 specific funnction that executes CLFLUSH. Mre info on CLFLUSh: https://c9x.me/x86/html/file_module_x86_id_30.html
            clflush_cache_range(hammerRow0,sizeof(char));
            read_midvalue = hammerRow0[0]; //Reading the first value present in the page
            
            
            //hammerRow1 access
            clflush_cache_range(hammerRow1,sizeof(int));
            read_midvalue = hammerRow1[0]; //Reading the first value present in the page
        }


        //Checking the victim row for errors
        for(i = 0; i < page_size / sizeof(int); i++){
            victimRow_data = victimRow[i];
            if(victimRow_data != default_value){
                printk(KERN_ALERT "victimRow Fault (After Hammering) at index %d: Present Value: %x \t Expected Value: %x:\tRow numer %d\n",i,0xff,counter);
                fault = 1;
            }
        }


        if(fault == 1){
            printk(KERN_ALERT "Rowhammer Test Failed\n");
            return 0;
        }
        else {
            //printk(KERN_ALERT "Rowhammer Test Passed for Row %d\n",counter);
        }


    }
    printk(KERN_ALERT "Rowhammer Test Passed\n");
    return 0;
}

static void __exit hello_exit(void){
    printk(KERN_INFO "Memory Test Exit!\n");
}

module_init(hello_entry);
module_exit(hello_exit);

//Licensing Info
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jonvonton");
MODULE_DESCRIPTION("Rowhammer Testing");

解决方法

alloc_pages 和 family 支持的最大页面大小为 2 的 MAX_ORDER 次方。 MAX_ORDER 通常为 11,除非被 CONFIG_FORCE_MAX_ZONEORDER 内核配置覆盖(仅针对某些架构设置,并且可以手动配置)。

MAX_ORDER 值为 11 允许分配 2048 个页面,对于最常用的页面大小 4096,允许最大分配大小为 8388608 (8 MiB)。

我不知道如何确定 DRAM 行大小,但它可能与系统页面大小无关,因为后者由架构的 MMU 决定(大多数架构为 4096)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。