Skip to content
Advertisement

Allocating physically contiguous pages in Kernel Module

I am trying to allocate physically contiguous pages in DRAM using the alloc_pages_exact function. When I try to allocate 10MB of pages, the returned address is always 0. But when I try to allocate 1MB of pages, the allocation is almost immediate. Also, can someone please tell me how to find the exact row size of DRAM? I had to search the datasheet of my RAM to figure it out. I was wondering if there is a command to determine the row size of DRAM. Earlier I thought that the System page size should be the DRAM row size as well, but the System page size turned out to be 4kB and my calculated row size came to be 8kB. Please help. Code:

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: %ldn", 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: %ldn", page_size);
    printk(KERN_ALERT "Cache Line Size: %dn", 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 Startsn");
    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 Startsn");
        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 %dn", i, victimRow_data, 0xff, counter);
                fault = 1;
            }
        }


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


    }
    printk(KERN_ALERT "Rowhammer Test Passedn");
    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");

Advertisement

Answer

The maximum size in pages supported by alloc_pages and family is 2 to the power of MAX_ORDER. MAX_ORDER is usually 11 unless overridden by the CONFIG_FORCE_MAX_ZONEORDER kernel configuration (which is only set for some architectures, and it may be manually configurable).

A MAX_ORDER value of 11 allows 2048 pages to be allocated, which for the most usual page size of 4096 allows a maximum allocation size of 8388608 (8 MiB).

I have no idea how to determine the DRAM row size, but it probably is not related to the system page size because the latter is determined by the architecture’s MMU (and is 4096 for most architectures).

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement