我正在开发 IA64 的 Linux 模块。我当前的问题是驱动程序使用 PAGE_SIZE 和 PAGE_SHIFT 宏进行 dma 页面分配。我遇到的问题是编译驱动程序的机器不是运行驱动程序所需的机器。因此,如果编译计算机上的 PAGE_SIZE 为 2^14K,而目标计算机为 2^16K,则驱动程序将失败。
我不想把这个问题变成一个关于在不是运行模块的机器上编译模块的“最佳实践”问题。我理解这方面的问题。我发现人们大多使用 getpagesize() 或 sysconf(_SC_PAGE_SIZE)。这两个选项不在 ia64 内核头文件中,所以我无法使用它们。还有其他方法可以获取运行时 PAGE_SIZE 吗?
我正在寻找的选项:
一种近似的方法是读取
/proc/meminfo
并检查 Mapped
大小(目前我的为 52544 kB),然后检查 nr_mapped
中的 /proc/vmstat
(目前我的为 131136 kB)。最后PAGE_SIZE = Mapped/nr_mapped
。有时这会给你一个准确的值(如我引用的当前示例),有时它是近似值,但非常接近。
希望这有帮助!
查找页面大小的一种方法是从进程的 smap 中获取它。
例如:
cd /proc/1
grep -i pagesize smaps
输出:
KernelPageSize: 4 kB
MMUPageSize: 4 kB
如果您尝试构建内核模块,则至少需要为模块将在其上运行的内核配置的内核标头。这些将定义您需要的页面大小宏。如果您没有正确配置标头,内核将拒绝加载您的模块。
在一台机器上编译模块以在另一台机器上运行并没有什么问题,即使它是不同的架构。您只需要根据正确的内核源代码进行构建即可。
这就是我最终所做的:
PAGE_SIZE (PAGE_SIZE = 1 << PAGE_SHIFT)
PAGE_SHIFT
API 获取当前系统 getconf
。该包装器获取当前系统页面移位并将其作为模块参数传递。 现在该模块正在具有不同 PAGE_SIZE 的不同架构上加载,没有任何问题。
我担心这是不可能的,因为页面大小是内核的一部分定义的。 如果您还使用工具链来编译内核模块,则需要了解页面大小。
所以至少在当前的内核架构下,这是不可能的。
您可以运行一个测试,只需映射一个具有不同偏移量的文件,然后看看哪个失败。虽然在内核模块中可能很烦人,但也许还有其他类似的测试可以使用。
为了在 Linux 内核模块代码中拥有正确的页面大小(如果不需要 getconf PAGESIZE...?),您应该做的是从 meminfo 和 vmstat 中找到最接近的 n^2 指数。
有一种正确的方法可以实现此目的,即使用 bc 命令中的对数,如下所示:
_x=$(grep Mapped /proc/meminfo | head -n 1 | tr -s ' ' | cut -d ' ' -f 2); _x=$(echo "l($_x)/l(2)" | bc -l | cut -d '.' -f 1); _x=$(printf "%.0f" "$_x"); echo "$_x";
18
对 /proc/vmstat 中的 nr_mapped 值执行相同的操作:
_y=$(grep nr_mapped /proc/vmstat | cut -d ' ' -f 2); _y=$(echo "l($_y)/l(2)" | bc -l | cut -d '.' -f 1); _y=$(printf "%.0f" "$_y"); echo "$_y";
16
最后,由于您有两个基于 kB 的值的指数,您可以将它们的最终结果除以并乘以 1024,以获得以字节为单位的页面大小:
echo $((2**$_x/2**$_y*1024));
4096