从表面上看,这似乎是一个愚蠢的问题.请耐心等.. :-)我将这个qs分为两部分:
第1部分: 我完全理解平台RAM映射到内核段; 特别是在64位系统上,这将运作良好.因此每个内核虚拟地址实际上只是物理内存(DRAM)的偏移量.
另外,我的理解是,由于Linux是一个现代虚拟内存操作系统,(几乎所有)所有地址都被视为虚拟地址,必须在运行时通过硬件"TLB/MMU",然后通过TLB/MMU进行转换通过内核分页表.同样,易于理解用户模式进程.
但是,内核虚拟地址怎么样?为了提高效率,直接映射这些并不简单(并且身份映射确实从PAGE_OFFSET开始设置).但是,在运行时,内核虚拟地址必须通过TLB/MMU并正确转换?实际情况如此吗?或者内核虚拟地址转换只是一个偏移计算?(但那怎么可能,因为我们必须通过硬件TLB/MMU?).举个简单的例子,我们考虑一下:
char *kptr = kmalloc(1024, GFP_KERNEL);
Run Code Online (Sandbox Code Playgroud)
现在kptr是一个内核虚拟地址.我知道virt_to_phys()可以执行偏移计算并返回物理DRAM地址.但是,这是实际问题:它不能通过软件以这种方式完成 - 这可能会很慢!所以,回到我之前的观点:它必须通过硬件(TLB/MMU)进行翻译. 这是真的吗?
第2部分: 好的,让我们说是这种情况,我们确实在内核中使用分页来做到这一点,我们当然必须设置内核分页表; 据我所知,它的根源在于swapper_pg_dir.
(我也理解vmalloc()与kmalloc()不同是一种特殊情况 - 它是一个纯虚拟区域,仅在页面错误时才被物理帧支持).
如果(在第1部分中)我们得出结论内核虚拟地址转换是通过内核分页表完成的,那么内核分页表(swapper_pg_dir)到底是如何"附加"或"映射"到用户模式进程?这应该发生在上下文切换代码中?怎么样?哪里?
例如.在x86_64上,2个进程A和B是活动的,1个cpu.A正在运行,因此它是更高规范的addr
0xFFFF8000 00000000 through 0xFFFFFFFF FFFFFFFF "映射"到内核段,它是低级规范的addr
0x0 through 0x00007FFF FFFFFFFF 映射到它的私有用户空间.
现在,如果我们上下文切换A-> B,进程B的低规范区域是唯一的但是它必须"映射"到同一个内核当然!这究竟是怎么发生的?在内核模式下,我们如何"自动"引用内核分页表?或者这是一个错误的陈述?
感谢您的耐心,非常感谢您深思熟虑的答案!
在ARM的内核oops中跟踪日志打印在内核日志中 -
<1>[ 4205.112835] I[0:swapper/0:0] [c0] Unable to handle kernel paging request at virtual address ff898580
<1>[ 4205.112874] I[0:swapper/0:0] [c0] pgd = ec3c4000
<1>[ 4205.112901] I[0:swapper/0:0] [c0] [ff898580] *pgd=00000000
<0>[ 4205.112939] I[0:swapper/0:0] [c0] Internal error: Oops: 80000005 #1] PREEMPT SMP ARM
Run Code Online (Sandbox Code Playgroud)
有时这个代码是oops -
Internal error: Oops - undefined instruction: 0 [#1] PREEMPT SMP ARM
Run Code Online (Sandbox Code Playgroud)
它在大多数日志中是 -
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
Run Code Online (Sandbox Code Playgroud)
有人可以解释这段代码的用途及其含义吗?
目标:模仿Qemu特别支持的"sabrelite:飞思卡尔i.MX6 Quad SABRE Lite Board(Cortex A9)"(做'qemu-system-arm -M?'它出现).
Qemu ver:2.10.1(主持人:fedora-27).
我已成功交叉编译并构建了一个4.1.46 Linux内核(使用了imx_v6_v7_defconfig配置文件)以及一个简单的"骨架"根文件系统(基于busybox).(仅供参考,我对ARM Cortex-A9 Versatile Express平台有类似的工作设置 - 我使用自己的家用旋转嵌入式Linux系统SEALS进行此操作.
看看类似主板使用的U-Boot配置文件,我想用'root =/dev/mmcblk0p0'作为内核的root = param.所以,为了尝试一下,我按如下方式运行qemu(pl水平滚动以查看):
qemu-system-arm -m 512 -M sabrelite -kernel zImage -drive file=rfs.img,format=raw -append "console=ttymxc0 rootfstype=ext4 root=/dev/mmcblk0p0 rw rootwait init=/sbin/init " -nographic -dtb imx6dl-sabresd.dtb
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.1.46 (kai@klaptop) (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29) ) #2 SMP Mon Nov 27 17:16:22 IST 2017
[ 0.000000] …Run Code Online (Sandbox Code Playgroud)