0

I am trying to make a kernel module that gives me some basic information about the memory, like nodes, zones, pages, etc. I am not able to build the module, there are some errors. I am using Ubuntu 20.04. Kernel 5.8.0-55-generic.

The code is as follows:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/mmzone.h>

static int __init hello_entry(void){

    pg_data_t* pgdat;

    for_each_online_pgdat(pgdat){

        printk("KERN_ALERT" "Number of Zones: %d\n", pgdat->nr_zones);

    }

    printk("KERN_ALERT" "Hello World Entry!\n");
    return 0;
} 

static void __exit hello_exit(void){
    printk("KERN_ALERT" "Hello World Exit!\n");
}

module_init(hello_entry);
module_exit(hello_exit);

Make File output:

root@madhur-VivoBook:/media/madhur/CommonSpace/Work/Linux/KernelModule# make
make -C /lib/modules/5.8.0-55-generic/build M=/media/madhur/CommonSpace/Work/Linux/KernelModule modules
make[1]: Entering directory '/usr/src/linux-headers-5.8.0-55-generic'
  MODPOST /media/madhur/CommonSpace/Work/Linux/KernelModule/Module.symvers
WARNING: modpost: missing MODULE_LICENSE() in /media/madhur/CommonSpace/Work/Linux/KernelModule/hello.o
ERROR: modpost: "next_online_pgdat" [/media/madhur/CommonSpace/Work/Linux/KernelModule/hello.ko] undefined!
ERROR: modpost: "first_online_pgdat" [/media/madhur/CommonSpace/Work/Linux/KernelModule/hello.ko] undefined!
make[2]: *** [scripts/Makefile.modpost:111: /media/madhur/CommonSpace/Work/Linux/KernelModule/Module.symvers] Error 1
make[2]: *** Deleting file '/media/madhur/CommonSpace/Work/Linux/KernelModule/Module.symvers'
make[1]: *** [Makefile:1698: modules] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.8.0-55-generic'
make: *** [Makefile:5: all] Error 2

next_online_pgdat and first_online_pgdat are defined in the mmzone.h file, yet there is this message that they are undefined.

I am trying to write a module for the first time, so it would be very helpful if someone could suggest some resources for the Linux kernel module programming, specifically memory management. I actually want to allocate and access physical memory pages and do some stuff with them.

Update: Thanks to @Tsyvarev. Now my code looks like this:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
#include <asm/cacheflush.h>

static int __init hello_entry(void){
    printk(KERN_ALERT "Hello World Entry!\n");

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

    int i;

    int number_of_pages = 3;

    int* pages = (int *)alloc_pages_exact(number_of_pages * PAGE_SIZE, __GFP_DMA);

    int *prev_page, *rowhammer_page, *next_page;

    prev_page = pages;
    rowhammer_page = prev_page + PAGE_SIZE;
    next_page = rowhammer_page + PAGE_SIZE;


    for(i = 0; i < PAGE_SIZE / sizeof(int); i++){
        prev_page[i] = i;
        rowhammer_page[i] = i;
        next_page[i] = i;
    }


    clflush_cache_range(rowhammer_page, PAGE_SIZE);//Flush rowhammer_page from cache(Will this flush from all cache?)
        
    int read_midvalue = rowhammer_page[PAGE_SIZE / (sizeof(int) * 2)]; //Reading the middle value present in the page
    
    if(read_midvalue != PAGE_SIZE / (sizeof(int) * 2)){
        printk(KERN_ALERT "Rowhammer Fault on access number %d\n", i);
    }



    return 0;
} 

static void __exit hello_exit(void){
    printk(KERN_ALERT "Hello World Exit!\n");
}

module_init(hello_entry);
module_exit(hello_exit);

This compiles well, but when I do insmod hello.ko, the log shows that clflush_cache_range is an unknown symbol. Here is the log:

[ 1246.489806] hello: loading out-of-tree module taints kernel.
[ 1246.489812] hello: module license 'unspecified' taints kernel.
[ 1246.489814] Disabling lock debugging due to kernel taint
[ 1246.489903] hello: module verification failed: signature and/or required key missing - tainting kernel
[ 1246.490039] hello: Unknown symbol clflush_cache_range (err -2)

I am using an x86 machine.

jonvonton
  • 13
  • 2
  • There are plenty of functions in the Linux kernel, but kernel **modules** can use only **exported** ones. The function is exported using `EXPORT_SYMBOL` macro or similar. Usually, exporting function is performed in the same source file where the function is defined. The functions you are trying to use are defined in the file [mm/mmzone.c](https://elixir.bootlin.com/linux/v5.8.18/source/mm/mmzone.c), as you can see there is no EXPORT_SYMBOL in that file. See also [that question](https://stackoverflow.com/questions/39691131/undefined-functions-while-compiling-linux-kernel-module). – Tsyvarev Jun 24 '21 at 07:06
  • @Tsyvarev Thanks for the help! So now I know that I can use only the symbols present in kallsyms file. So I used a couple of them to do what I want to. However, there is a function clflush_cache_range which is exported and present in kallsyms file but the compiler says that it is unable to recognize it. – jonvonton Jun 25 '21 at 06:03
  • 1
    The function `clflush_cache_range` is exported using `EXPORT_SYMBOL_GPL`, so it is available only for **GPL**-licensing modules. The license is set using `MODULE_LICENSE` macro. BTW, the warning you got is exactly about the license. – Tsyvarev Jun 25 '21 at 06:07
  • And no, a presence of a symbol in `proc/kallsyms` has no relation with the exporting the symbol. See that [my answer](https://stackoverflow.com/a/32968237/3440745). – Tsyvarev Jun 25 '21 at 06:09

0 Answers0