57

I am working on a Linux module for IA64. My current problem is that the driver uses the PAGE_SIZE and PAGE_SHIFT macros for dma page allocation. The problem I am having is that the machine compiling the driver is not the ones that needed to run the driver. So, if the PAGE_SIZE on the compiling machine is 2^14K and the destination machine is 2^16K then the driver fails.

I don't want to turn this question into a 'best practice' issue about compiling modules on machines which are not the ones running the modules. I understand the issues about that. What I found is that people mostly uses getpagesize() or sysconf(_SC_PAGE_SIZE). These two options are out of the ia64 kernel headers so I can't use them. Is there another way that I could get the runtime PAGE_SIZE?

Options I am looking at:

  • Reading some file in /proc?
  • syscall?
  • Other function that let me calculate the PAGE_SIZE by inference (e.g ORDER, getpageshift, etc)?
  • Other?
xiay
  • 855
  • 8
  • 19
Freddy
  • 3,064
  • 3
  • 26
  • 27
  • Are you saying the `PAGE_SIZE` is configurable for the IA64 architecture, and not fixed? I thought `PAGE_SIZE` was fixed for a given architecture (e.g. always `4096` for x86). – Craig McQueen Apr 10 '13 at 00:54
  • IA64 does indeed support multiple page sizes: http://www.informit.com/articles/article.aspx?p=29961&seqNum=3 – mdd Mar 24 '15 at 01:59

7 Answers7

72

Try using the getconf utility, which will allow you to retrieve the page size, in bytes, easily.

getconf PAGESIZE

Example output, in bytes:

4096
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
vetri
  • 919
  • 8
  • 6
  • 4
    I don't think this answers the OP's question, but it's helpful info since sysconf(_SC_PAGESIZE) appears to return 4K on linuxia64 (while mprotect fails on a page not aligned on a 16K boundary). – Peeter Joot Nov 28 '14 at 23:56
  • 3
    my x86-64 only returns 4k, but it has 4k, 2M, and 1G pages. – ctrl-alt-delor Aug 03 '19 at 14:04
  • Works on my Ubuntu 18.04 machine, but not in an embedded Linux board I have. The embedded Linux board says: `bash: getconf: command not found`. Note that the embedded Linux board uses Busybox. [This answer](https://stackoverflow.com/a/49030069/4561887) works on my embedded Linux board instead. – Gabriel Staples Aug 31 '22 at 06:44
21

One approximate method is to read /proc/meminfo and check Mapped size ( on mine its 52544 kB as of now ) and then check nr_mapped in /proc/vmstat ( on mine its 131136 as of now ). Finally PAGE_SIZE = Mapped/nr_mapped. Sometimes this gives you an accurate value ( as in the current example I've quoted ) and sometimes its approximate but very close. Hope this helps!

Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
  • 2
    I did not find `Mapped/nr_mapped` even close to what was provided by `getconf PAGESIZE` – MCP Jun 19 '18 at 21:25
  • @MCP On my machine the `Mapped/nr_mapped = 379512KB/94878 = 4KB`. And `getconf PAGESIZE` gives 4096. They do match. Could you share what you saw? – smwikipedia Dec 26 '21 at 12:08
  • Assuming kB: `echo "$(( $(grep Mapped: /proc/meminfo | awk '{ print $2 }') * 1024 / $(grep nr_mapped /proc/vmstat | awk '{ print $2 }') ))"` – Banyoghurt Apr 01 '22 at 16:05
15

One way to find the page size is to obtain it from smaps for a process.

For example:

cd /proc/1
grep -i pagesize smaps

Output:

KernelPageSize:        4 kB
MMUPageSize:           4 kB
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
ria
  • 339
  • 2
  • 9
  • Curiously using your trick I see `4 kB` on an ARM, but inside `arch/arm/include/asm/page.h` of the running kernel it's `#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)` and evidently it _is_ 1024 Bytes when checking from my driver, as already suggested by the define `page.h`. What gives? – 0xC0000022L Oct 31 '19 at 11:06
  • This *does* work on my embedded Linux board as well, unlike `getconf PAGESIZE` which does not. It also works on Ubuntu, but note that for the `grep` part of the command you must use `sudo grep`. – Gabriel Staples Aug 31 '22 at 06:47
7

If you are trying to build a kernel module, you will need to have at least the kernel headers that are configured for the kernel the module will run on. Those will define the page size macros you need. If you don't have the correctly configured headers, the kernel will refuse to load your module.

And there is nothing wrong with compiling a module on one machine to run on another, even if it's a different architecture. You just need to build against the correct kernel source.

JayM
  • 4,798
  • 1
  • 21
  • 15
  • It is not an issue about kernel sources. It is about loading a module compiled on a machine, to run into another machine (Both have the same kernel version but configured differently). I don't want to re-compile against the new configuration because PAGE_SIZE changed. I am looking to get that parameter from the kernel as an API, not as a MACRO (which is solved at compile time). – Freddy Mar 17 '11 at 20:01
  • PAGE_SIZE is very fundamental and required for a module while building the module itself.. – kumar May 10 '11 at 05:45
6

This is what I finally did:

  • Re-work my current module to take a new module parameter called page_shift and used that to calculate the PAGE_SIZE (PAGE_SIZE = 1 << PAGE_SHIFT)
  • Created a module loader wrapper which gets the current system PAGE_SHIFT using getconf API from libc. This wrapper gets the current system page shift and pass it as a module parameter.

Right now the module is being loaded on different architectures with different PAGE_SIZE without any problems.

Freddy
  • 3,064
  • 3
  • 26
  • 27
  • 2
    Noob question. Could you explain a little more about wrapper which uses getconf API? I mean did you called getconf command inside popen() function or something. A little more light over it will be super appreciated. – Dr. Xperience Dec 07 '16 at 19:34
0

You could just run a test, just mmap a file with different offsets and see which fail. Might be annoying in a kernel module though, but maybe there is some other test like that you could use.

Justin Cormack
  • 1,226
  • 12
  • 8
0

I fear that it is impossible to do as page size is something defined as part of the kernel. page size knowledge is required in case of toolchain also which you use to compile the kernel module.

So atleast with current kernel architecture, it is impossible to do so.

kumar
  • 2,530
  • 6
  • 33
  • 57