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

Allocating physically contiguous pages in Kernel Module

我正在尝试使用 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, victimRow_data, 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 和系列支持的最大页面大小是 2 的 MAX_ORDER 次方。 MAX_ORDER 通常为 11,除非被 CONFIG_FORCE_MAX_ZONEORDER 内核配置覆盖(仅针对某些体系结构设置,并且可以手动配置)。

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

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