-
zt_eygle_Linux虚拟内存管理 - page table页表的作用
2013-05-13 16:57:48http://www.eygle.com/digest/2012/05/linux_page_table.html ...http://www.eygle.com/digest/2012/05/linux_page_table.html来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9240380/viewspace-760959/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/9240380/viewspace-760959/
-
深入理解linux内存管理之 页表管理
2019-07-25 10:21:56页表是内存管理系统中的数据结构,用于...在使用虚拟地址空间的linux操作系统上,每一个进程都工作在一个4G的地址空间上,其中0-3G是应用进程可以访问的user地址空间,是这个进程独有的,其他进程看不到也无法操作这...页表是内存管理系统中的数据结构,用于向每个进程提供一致的虚拟地址空间,每个页表项保存的是虚拟地址到物理地址的映射以及一些管理标志。应用进程只能访问虚拟地址,内核必须借助页表和硬件把虚拟地址翻译为对物理地址的访问。
页表作用
在使用虚拟地址空间的linux操作系统上,每一个进程都工作在一个4G的地址空间上,其中0-3G是应用进程可以访问的user地址空间,是这个进程独有的,其他进程看不到也无法操作这个地址空间;3G~4G是kernel地址空间,所有进程共享这部分地址空间。
由于每个进程都有3G的私有进程空间,所以系统的物理内存无法对这些地址空间进行一一映射,因此kernel需要一种机制,把进程地址空间映射到物理内存上。当一个进程请求访问内存时,操作系统通过存储在kernel中的进程页表把这个虚拟地址映射到物理地址,如果还没有为这个地址建立页表项,那么操作系统就为这个访问的地址建立页表项。最基本的映射单位是page,对应的是页表项PTE
页表项和物理地址是多对一的关系,即多个页表项可以对应一个物理页面,因而支持共享内存的实现(几个进程同时共享物理内存)。
页表的实现
实现虚拟地址到物理地址转换最容易想到的方法是使用数组,对虚拟地址空间的每一个页,都分配一个数组项。但是有一个问题,考虑IA32体系结构下,页面大小为4KB,整个虚拟地址空间为4GB,则需要包含1M个页表项,这还只是一个进程,因为每个进程都有自己独立的页表。因此,系统所有的内存都来存放页表项恐怕都不够。
相像一下进程的虚拟地址空间,实际上大部分是空闲的,真正映射的区域几乎是汪洋大海中的小岛,因次我们可以考虑使用多级页表,可以减少页表内存使用量。实际上多级页表也是各种体系结构支持的,没有硬件支持,我们是没有办法实现页表转换的。
为了减少页表的大小并忽略未做实际映射的区域,计算机体系结构的设计都会靠虑将虚拟地址划分为多个部分。具体的体系结构划分方式不同,比如ARM7和IA32就有不同的划分,在这里我们不讨论这部分内容。
Linux操作系统使用4级页表
图中CR3保存着进程页目录PGD的地址,不同的进程有不同的页目录地址。进程切换时,操作系统负责把页目录地址装入CR3寄存器。地址翻译过程如下
-
对于给定的线性地址,根据线性地址的bit22~bit31作为页目录项索引值,在CR3所指向的页目录中找到一个页目录项。
-
找到的页目录项对应着页表,根据线性地址的bit12~bit21作为页表项索引值,在页表中找到一个页表项。
-
找到的页表项中包含着一个页面的地址,线性地址的bit0~bit11作为页内偏移值和找到的页确定线性地址对应的物理地址。
这个地址翻译过程完全是由硬件完成的。
页表格式
页目录项和页表项大小都是32bit(4 bytes),由于4KB地址对齐的原因,页目录项和页表项只有bit12~bit31用于地址,剩余的低12bits则用来描述页有关的附加信息。
作者:kernel_dsn
来源:CSDN
原文:https://blog.csdn.net/u011209099/article/details/9248525
版权声明:本文为博主原创文章,转载请附上博文链接! -
-
mmu以及页表 linuxkernel(2)
2017-02-06 18:34:10对于mmu的作用,参看第一篇的介绍 这里讲linux kenel的mmu和页表 linux有两次页表处理 第一次是在arch/arm/kernel/head.s里面 第二次是是在start_kernel以后 还有其他的一些io地址映射 第一次在arch/arm/...对于mmu的作用,参看第一篇的介绍
这里讲linux kenel的mmu和页表
部分内容图片参考 http://blog.csdn.net/luckyapple1028/article/details/45287617 非常不错的blog
对于1M段大小的虚拟地址和物理地址转换,arm1176计算方式如下
-
虚拟地址的[31:20]位存放一级页表的入口index,[19:0]位存放段偏移;
-
从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;
-
一级页表基址+ VA[31:20] = 该虚拟地址对应的页表描述符的入口地址;
-
页表描述符的[31:20]位为该虚拟地址对应的物理段基址;
-
物理段基址+ VA[19:0]段偏移= 物理地址
linux有两次页表处理
第一次是在arch/arm/kernel/head.s里面
第二次是是在start_kernel以后
还有其他的一些io地址映射
内核解压到了0x8000处,并且从0x8000开始执行
第一次在arch/arm/kernel/head.s
/* * Setup the initial page tables. We only setup the barest * amount which are required to get the kernel running, which * generally means mapping in the kernel code. * * r8 = phys_offset, r9 = cpuid, r10 = procinfo * * Returns: * r0, r3, r5-r7 corrupted * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) */ __create_page_tables: pgtbl r4, r8 @ page table address /* * Clear the swapper page table */ mov r0, r4 mov r3, #0 add r6, r0, #PG_DIR_SIZE 1: str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 teq r0, r6 bne 1b
其中pgtbl
.macro pgtbl, rd, phys add \rd, \phys, #TEXT_OFFSET sub \rd, \rd, #PG_DIR_SIZE .endm
这里明确说明建立的页表只是为了kernel能够运行,因此只映射kernel code.
输入的时候 r8是物理地址偏移(0) r9是cpuid r10是procinfo
返回值r4是页表基地址(0x4000)
下面来看这个操作过程
pgtbl r4,r8被展开为add r4,r8,#TEXT_OFFSET 表示内核起始地址相对于RAM地址的偏移值 (定义在arch/arm/Makefile中 TEXT_OFFSET := $(textofs-y) textofs-y:= 0x00008000 )
sub r4,r4,#PG_DIR_SIZE 表示页目录的大小。
我这里变成
ADD R4, R8, #0x8000
SUB R4, R4, #0x40000x4000是页目录的大小为16KB
0x8000表示内核起始地址相对于RAM地址的偏移值
r4=r8+0x8000-0x4000
得到r4等于物理页表的起始地址
后面就是循环清空这一块地址 从r4->r4+0x4000。全部清0
ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags /* * Create identity mapping to cater for __enable_mmu. * This identity mapping will be removed by paging_init(). */ adr r0, __turn_mmu_on_loc ldmia r0, {r3, r5, r6} sub r0, r0, r3 @ virt->phys offset add r5, r5, r0 @ phys __turn_mmu_on add r6, r6, r0 @ phys __turn_mmu_on_end mov r5, r5, lsr #SECTION_SHIFT mov r6, r6, lsr #SECTION_SHIFT
从proc结构中取出mm_mmuflags标记放到r7中(0xc0e)__turn_mmu_on_loc: .long . .long __turn_mmu_on .long __turn_mmu_on_end
将__trun_mmu_on_loc地址存放到r0中 也就是r0指向这个3个long字节的数据第一个 r0=0x8168
从r0中取出数据来放到r3 r5 r6中 adr是取得运行时的相对地址。此时r0是相对地址
第一个.表示当前位置 也就是__trun_mmu_on_loc的值=r3(0xc0008168),第二个是__turn_mmu_on函数的起始地址=r5(0xc0008200),第三个是__turn_mmu_on函数的结束地址=r6(0xc0008220)这些地址都是虚拟地址,是0XC0000000起头的地址
sub r0,r0,r3 r0=r0-r3 相对的运行地址r0-绝对的0XC000XXX地址r3得到两者之间的偏移
然后 r5和r6这两个绝对地址0XC0000XXX 都加上这个偏移。就得到了当前物理内存中的__turn_mmu_on(0x8200)和__turn_mmu_on_end(0x8220)的地址
然后将r5 r6的物理地址都右移20位,这样r5和r6里面保存的就是__trun_mmu_on和__trun_mmu_on_end的物理基地址的索引。(r5=r6=0)
比如R5=0X123ABCDE。按照1M分段。那么0x123就是[31:20]的基地址。0xABCDE就是段内偏移。
R5右移20位后变成了0X123
1: orr r3, r7, r5, lsl #SECTION_SHIFT @ flags + kernel base str r3, [r4, r5, lsl #PMD_ORDER] @ identity mapping cmp r5, r6 addlo r5, r5, #1 @ next section blo 1b
接下来先将 R5左移20位 然后或上r7,也就是0X12300000 or r7,此时r5还是没有变,依然是0X123。也就是描述符标记,形成了一个4字节的页表描述符(0xc0e),放到R3当中。str r3 ,[r4,r5, lsl #2]等同于r4[r5*4]=r3。也就是将这个描述符放到相应的位置上去。循环直到R6停止。
到这里为止
turn_mmu_on到turn_mmu_end的代码所属的物理位置的页表描述符已经设置好了
这样就做到了虚拟地址和物理地址一一映射。因为要保证执行完turn_mmu_on以后,这部分代码依然是一一映射的,开启完毕以后即使在虚拟地址上也可以执行后续的代码
实际上我的树莓派中R5=0因此就是 r4[0]=0xc0e如下图
接下来是映射内核从开始映射到末尾.bss段
/* * Map our RAM from the start to the end of the kernel .bss section. */ add r0, r4, #PAGE_OFFSET >> (SECTION_SHIFT - PMD_ORDER) ldr r6, =(_end - 1) orr r3, r8, r7 add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER) 1: str r3, [r0], #1 << PMD_ORDER add r3, r3, #1 << SECTION_SHIFT cmp r0, r6 bls 1b
在我的反汇编代码中变成了
.head.text:C000811C ADD R0, R4, #0x3000 .head.text:C0008120 LDR R6, =0xC08F269F .head.text:C0008124 ORR R3, R8, R7 .head.text:C0008128 ADD R6, R4, R6,LSR#18 .head.text:C000812C .head.text:C000812C loc_C000812C ; CODE XREF: __create_page_tables+7Cj .head.text:C000812C STR R3, [R0],#4 .head.text:C0008130 ADD R3, R3, #0x100000 .head.text:C0008134 CMP R0, R6 .head.text:C0008138 BLS loc_C000812C
PAGE_OFFSET=0XC0000000
SECTION_SHIFT=20
PMD_ORDER=2
首先将PAGE_OFFSET(0xc0008000)右移20-2 ,再加上r4(页表物理基地址)得到内核起始链接地址对应页表项的物理地址,保存到r0中
r0等于0x7000
r4=0x4000
将.end结束地址放到R6当中
将R7|R8的值保存到 R3中。
然后计算内核结束虚拟地址对应应页表项的物理地址保存到r6中
每一次循环都会将r3增加一个1<<SECTION_SHIFT 的大小,也就是增加1MB将描述符填充到页表对应的位置里面
r4=pagetable=0x4000
为什么要用 addr>>(20-2)+pagetable 得到内核起始地址和结束地址在pagetable对应的页表项地址呢?
这个-2是因为一个页表项占用4字节,也就是左移两位,相当于乘以4
比如要计算0XC0008000 先取得高12bit 0xC00,这个就是索引。访问的时候就是访问pagetable[0XC00]项,每一项四个字节,
pagetable[0xc00]=pagetable+(0xc0008000>>20)*4=pagetable+0xc0008000>>20<<2=pagetable+0xc0008000>>(20-2)=0x4000+0xc0008000>>18
以R3为基准,每次增加1MB大小。
比如 R3=0X00000C0E pagetable[0xc00]=0X00000C0E
R3=R3+0X100000
R3=0x00100C0E pagetable[0xc00]=0X00100C0E
R3=R3+0X100000
R3=0x00200C0E pagetable[0xc00]=0X00200C0E
pagetable[0xc00] 开始处的内存如下图
到这里为止。我们映射了内核代码部分,也映射了turn_mmu_on部分
注意到页表地址0x7000里面是0x00000c0e 前面的0x4000里面也是0x00000c0e。那么就表示,这两个虚拟地址都映射到了同一个物理地址。
因此我们访问0xc0008000 和访问0x8000 访问的是同一块物理地址。
接下来就是映射参数地址了。r2 atag或者DTB
/* * Then map boot params address in r2 if specified. * We map 2 sections in case the ATAGs/DTB crosses a section boundary. */ mov r0, r2, lsr #SECTION_SHIFT movs r0, r0, lsl #SECTION_SHIFT subne r3, r0, r8 addne r3, r3, #PAGE_OFFSET addne r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER) orrne r6, r7, r0 strne r6, [r3], #1 << PMD_ORDER addne r6, r6, #1 << SECTION_SHIFT strne r6, [r3]
首先得到物理地址r2的高12bit。其实就是r0=r2&0xfff00000如果r0是0,后面就不再映射了,这里我的r0是0,所以后续的映射都没有执行。
因为我的r2是0x100,恰好和内核起始地址0x8000在同一个段内,所以在映射内核的时候就顺带映射了r2。
(疑问?如我我r2=0x100 内核的起始地址在0x100800,不在同一个段内那不是就没有映射了吗?)。
这个疑问暂留。
接下来一般就是return 了。
但是为了我们能够在start_kernel之前实现串口打印。通常可以通过配置CONFIG_DEBUG_LL实现
make menuconfig ---> Kernel hacking ---> 选中:Kernel debugging。
当选中Kernel debugging后,才能看见Kernel low-level debugging functions. 选中即可
所以在return之前可以映射一下串口地址。
/* * Map in IO space for serial debugging. * This allows debug messages to be output * via a serial console before paging_init. */ addruart r7, r3, r0 mov r3, r3, lsr #SECTION_SHIFT mov r3, r3, lsl #PMD_ORDER add r0, r4, r3 mov r3, r7, lsr #SECTION_SHIFT ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags orr r3, r7, r3, lsl #SECTION_SHIFT orr r3, r3, #PMD_SECT_XN str r3, [r0], #4
对于我的树莓派addruart的定义是
其中addruart实现的宏就是 r7存放UART需要映射的物理地址,R3存放映射后的虚拟地址,r0是一个临时变量,可供自由使用.macro addruart, rp, rv, tmp ldr \rp, =UART0_BASE ldr \rv, =IO_ADDRESS(UART0_BASE) .endm
并且在arm\mach-bcm2708\include\mach\platform.h里面找到了相关的定义
/* macros to get at IO space when running virtually */ #define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) #define BCM2708_PERI_BASE 0x20000000 #define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
BCM2708外设的基地址是 0X20000000, UART0口的基地址是 0X201000
所以只要映射 物理地址r7=0X20201000 到虚拟地址r3=IO_ADDRESS(0x20201000)=(0xF2201000)
IO的映射公式 是先取物理地址paddr的低28bit得到v1 ,取得最高位加到v1的[27:24] bit上,最后加上0xf0000000(映射到其他合适的虚拟地址应该也可以???)
首先r3=r3>>(20-2) 得到描述页表项相对于页表基地址的偏移。
r4是页表基地址 r0=r4+r3, 得到r0就是对应的描述页表项的物理地址。
接下来构造页表描述项
r3=r7>>20
再把物理地址r7右移20位放到R3中;
r7=io_mmu_flags
取出io_mmu_flags到r7中
r3=r3<<20 | r7
再或上另外一个标记PMD_SECT_XN
得到最终的页表项描述符 r3
然后把r3存储到r0地址中.(再把r0自增4 r0=r0+4,这个r0没有必要再+4了。没什么作用)
这样访问F2XXXXX的时候就会访问IO地址0X2XXXXXX了。
-
-
内核必须懂(七): Linux四级页表(x64)
2019-04-22 17:14:33Linux四级页表的作用主要就是地址映射, 将逻辑地址映射到物理地址. 很多时候, 有些地方想不明白就可以查看实际物理地址进行分析. Intel 四级页表 其实很多设计的根源或者说原因都来自于CPU的设计, OS很多...目录
- 前言
- Intel四级页表
- 实操寻址
- 获取cr3
- 获取PGD
- 获取PUD
- 获取PMD
- 获取PTE
- 获取内容
- 最后
前言
Linux四级页表的作用主要就是地址映射, 将逻辑地址映射到物理地址. 很多时候, 有些地方想不明白就可以查看实际物理地址进行分析.
Intel 四级页表
其实很多设计的根源或者说原因都来自于CPU的设计, OS很多时候都是辅助CPU. Linux的四级页表就是依据CPU的四级页表来设计的. 这里主要说的就是Intel x64页面大小为4KB的情况, 如图所示:
当然, 你可以用指令确认下:
getconf PAGE_SIZE
实操寻址
首先这里先贴出几个工具, fileview, dram, registers. 这些都是可以帮助快速获取地址的, 上一篇文章说的kgdb工具也是可以的, 就是麻烦一点, 你懂的. 具体内容就不贴了, 这里仅展示用户态的代码:
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #define BUFSIZE 4096 int main() { int fd, ret; char buf[BUFSIZE]; unsigned long int a = 0x1234567890abcdef; printf( "a=0x%016lX addr: %p \n", a, &a ); if ( (fd = open( "/proc/registers", O_RDONLY ) ) < 0 ) { fprintf( stderr, "Open /proc/registers file failed! \n" ); exit( EXIT_FAILURE ); } lseek( fd, 0L, SEEK_SET ); if ( (ret = read( fd, buf, sizeof buf - 1 ) ) < 0 ) { perror( "/proc/registers" ); exit( EXIT_FAILURE ); } buf[ret] = 0; close( fd ); puts( buf ); while ( 1 ); return(0); }
使用make指令编译工具, 插入dram.ko和registers.ko驱动模块. 编译运行用户态程序, 如图所示:
获取cr3
这之中最关键的是cr3地址以及局部变量地址, 这里看到, 变量地址是0x7ffdcbffaba8, 变量值是0x1234567890ABCDEF. cr3寄存器中地址是0x40c78000. 当然了, 按照CPU的图示, cr3肯定是指向PML4E. 在Linux当中, 第一级页表称为PGD, 当然是有历史原因的, 可以自行google. 所以Linux的四级页表分别是PGD -> PUD -> PMD -> PTE.
获取PGD
想要获取PGD中的内容需要通过计算. 这里先来处理一下局部变量地址. 首先写成二进制.
0x7ffdcbffaba8 0111 1111 1111 1101 1100 1011 1111 1111 1010 1011 1010 1000
然后按照Intel的设计, 重新整合.
011111111 111110111 001011111 111111010 101110101000
重新写成16进制:
ff 1f7 5f 1fa ba8
这就是只要用的offset. 因为每个单元是64-bits因此需要在序号基础上乘以8获得地址. 所以PGD地址为:
0x40c78000(cr3) + ff * 8 = 0x40c787f8
然后使用启动之前编译的小工具:
./fileview /dev/dram
输入之前计算出来的地址0x40c787f8, 就可以得到之中的内容, 也就是PUD, 从CPU图来说就是PDPTE:
获取PUD
这里获取到的是67 50 75 76 00 00 00 80, 但是注意, Intel是和显示顺序反过来的. 也就是76755067, 然后后面的12-bits是页面属性. 所以, 具体地址就是:
76755000 + 1f7 * 8 = 76755fb8
同样输入地址到工具, 得到67 80 E8 2C 00 00 00 00.
获取PMD
直接计算了:
2ce88000 + 5f * 8 = 2ce882f8
得到67 00 DD 48 00 00 00 00.
获取PTE
直接计算了:
48dd0000 + 1fa * 8 = 48dd0fd0
得到67 58 59 20 00 00 00 80.
获取内容
最后就可以获取到内容了:
20595000 + ba8 = 20595ba8
最后
当然了, 这次是在用户态下进行从线性地址到物理地址转换的, 如果是内核态有些地方会发生变化. 暂时写到这里, 内核态等后续的更新了. 喜欢记得点赞, 有意见或者建议评论区见~
-
内核必须懂(七): Linux四级页表(x64)
2019-04-22 17:14:33Linux四级页表的作用主要就是地址映射, 将逻辑地址映射到物理地址. 很多时候, 有些地方想不明白就可以查看实际物理地址进行分析. Intel 四级页表 其实很多设计的根源或者说原因都来自于CPU的设计, OS很多... -
linux将虚拟地址转物理地址的过程探索[页表]
2015-05-30 22:41:13先是原理简单的介绍下: Linux把物理内存分为了固定统一大小的块,称为page[页],一般为...page table的作用就是将进程操作的地址[虚拟地址]转换成物理地址。 Linux Memory Model ================== ---------- -
内存管理源码分析-内核页表的创建以及索引方式(基于ARM64以及4级页表)
2020-05-07 23:44:12页表的主要作用是完成虚拟地址到物理地址的转换,更详细的介绍可以参考这个优秀的博客,很好地介绍了页表的理论。Linux如何实现这个页表理论呢?以及如何进行寻址呢?本文将会结合代码,从代码出发,基于ARM64的架构... -
ARM64的启动过程之(二):创建启动阶段的页表
2015-10-13 20:54:52ARM64的启动过程之(二):创建启动阶段的...本文主要描述了ARM64启动过程中,如何建立初始化阶段页表的过程。我们知道,从bootloader到kernel的时候,MMU是off的(顺带的负作用是无法打开data cache),为了提高性能 -
MMU作用,linux进程间通信方式 进程切换原因步骤
2012-10-03 10:00:08MMU的作用有两个:地址翻译和地址保护 软件的职责是配置页表,硬件的职责是根据页表完成地址翻译和保护工作。 通过MMU的映射,则可实现程序完全运行在SDRAM之中。 通过MMU可实现不连续的物理地址空间映射为连续的... -
ARM Linux (S3C6410架构/2.6.35内核)的内存映射(四)
2013-08-05 13:45:51set_pte_ext()的作用是根据Linux给出的Linux版本页表项来填充Arm硬件版本的页表项。 对于s3c6410,set_pte_ext()函数由汇编宏armv6_set_pte_ext来实现,定义在proc-macros.S文件中。 进入函数时,参数分别为: r0: ... -
宋宝华Linux培训笔记-Linux内存管理
2018-08-26 11:24:51内存映射中最重要的是页表,页表除了找到虚地址对应的物理地址外,在对应这一行中还存有两个标志位,一个是RWX标志位,表明该位置是可读还是可写,另一个是u/k标志位,区分用户空间和内核空间。每个进程看到4G内存,... -
【Linux驱动】Linux内存映射机制(mmap实现)
2019-08-24 23:27:472、MMU的作用: (1)负责虚拟地址到物理地址的转换; 1)确定的数学公式进行转换; 2)用表格存储虚拟地址对应的物理地址: tiny210使用第二种方法,并根据每次转换时查表的次数分为一级页表方式(以段的方式... -
Linux内存讲解
2015-04-10 17:16:18简介程序和进程存储类别和作用域程序大小内存映射调用堆栈页表库内存限制内存分配实现细节参考文献 简介 在Linux下,所有的程序都在虚拟内存环境中运行。如果有某个C程序员将指针的值打印出来(在实践中从来... -
ARM Linux (S3C6410架构…
2013-08-27 11:59:48set_pte_ext()的作用是根据Linux给出的Linux版本页表项来填充Arm硬件版本的页表项。 对于s3c6410,set_pte_ext()函数由汇编宏armv6_set_pte_ext来实现,定义在proc-macros.S文件中。 进入函数时,参数分别为: r0... -
linux内核源码_Linux内核源码分析之set_arch (一)
2020-12-01 12:28:39概述之前已经写了几篇Linux内核启动相关的文章,比如:《解压内核镜像》《调用 start_kernel》都是用汇编语言写的,这些代码的作用仅仅是把内核镜像放置到特定的位置,同时配置好C语言的运行环境,再有就是简单的把... -
Linux操作系统学习笔记
2018-01-02 16:40:30Linux的pwd命令的作用是显示当前的工作目录 计算机中的执行过程是:取指令->指令译码->执行指令->修改指令计数器 在页式存储管理中,当前进程的页表起始地址存放在PTBR中(CPU中的一个控制寄存器,叫做页表基址... -
Linux内核源码+电子书
2011-02-21 15:13:101.5.2 Linux内核的作用 1.5.3 Linux内核的抽象结构 1.6 Linux内核源代码 1.6.1 多版本的内核源代码 1.6.2 Linux内核源代码的结构 1.6.3 从何处开始阅读源代码 1.7 Linux内核源代码分析工具 1.7.1 ... -
Linux——fork()函数
2017-03-11 20:59:41fork函数的功能fork函数的作用是创建一个与父进程几乎相同的进程,它们可以同时做相同的事情,当然也可以通过初始参数的不同来做不同的事情。 当进程调用fork函数时,内核会复制所有的内部数据结构,复制进程的页表... -
Linux内存管理方式
2020-08-19 23:23:55本质上是一种内存的划分方法 分页存储管理 这种方式中,将用户程序的地址空间,注意,是用户程序的地址空间分为若干个固定大小的区域,成为“页”或“页面”。我们可以知道,这也页其实是不存在的...作用:实现页号到. -
嵌入式linux内存管理
2009-02-26 12:28:001、MMU允许把虚拟地址映射到一个...4、MMU机制中,硬件-->页表的翻译和保护,软件-->配置页表。5、linux中,每个进程都有各自私用的(0~3GB)用户空间(地址空间)。6、1GB(3~4GB)内核空间为所有进程及内核共享。7、 -
linux进程内存布局
2012-01-11 12:18:10在多任务操作系统中的每一个进程都运行在一个属于它自己的内存沙盘中。这个沙盘就是虚拟地址空间(virtual address space),在32位模式下...只要虚拟地址被使能,那么它就会作用于这台机器上运行的所有软件,包括内核 -
Linux bootmem(2)
2020-05-04 17:50:16这个函数是系统入口调用的stext函数的一部分,属于最早期的和内存相关的函数,其作用是创建内核映射页表。由于在打开MMU时,有一个地址映射ON/OFF的切换过程,需要一段恒等映射(identity mapping,有资料翻译为一致... -
Linux内核源码分析之setup_arch (一)
2020-11-22 10:43:08之前已经写了几篇Linux内核启动相关的文章,比如:《解压内核镜像》《调用 start_kernel》都是用汇编语言写的,这些代码的作用仅仅是把内核镜像放置到特定的位置,同时配置好C语言的运行环境,再有就是简单的把内核... -
linux系统编程之线程.zip
2020-05-05 19:28:052. 从内核里看进程和线程是一样的,都有各自不同的PCB,但是PCB中指向内存资源的三级页表是相同的 3. 进程可以蜕变成线程 4. 线程可看做寄存器和栈的集合 5. 在linux下,线程最是小的执行单位;进程是最小的分配资源... -
Linux分页机制
2009-10-14 11:31:00分页机制 分页机制的作用 分页机制是在段机制之后进行的,它进一步将线性地址转换为物理地址。 80386使用4K字节大小的页,且每页的起始地址都被4K整除。因此,80386把4GB字节线性地址空间划分为1M个页面,采用了两级... -
Linux内核源码分析之setup_arch (三)
2020-12-31 10:31:55在 Linux内核源码分析之setup_arch (二) 中介绍了当前启动阶段的内存分配函数memblock_alloc,该内存分配函数在本篇将要介绍paging_init中用于页表和内存的分配,paging_init函数大致流程如下图所示。 2. paging_...
-
DP算法题收集汇总
-
华为1+X认证——网络系统建设与运维(初级)
-
PowerBI重要外部工具详解
-
MySQL 多实例安装 及配置主从复制实验环境
-
MaxScale 实现 MySQL 读写分离与负载均衡
-
Excel视频教学-百度网盘.txt
-
基于SSM的仿小米商城源码
-
React中Link跳转
-
项目经理成长之路
-
jadx反编译最新版下载
-
漏洞挖掘经验
-
凉了呀,面试官叫我设计一个排行榜。
-
HTTP加密实践
-
Samsung-SSD-SMART-ATTRIBUTES-APR16J.pdf
-
eclipse启动报错11or greater is requested解决
-
精通编译Makefile,Nina, 从底层uboot到Android
-
linux基础入门和项目实战部署系列课程
-
Visual C++ OPC Client Example.rar
-
sonar-scanner-msbuild-5.0.4.24009-net46.zip
-
Future&Fork&Join框架原理分析