ARMv8(aarch64)页表建立过程详细分析

37 篇文章 2 订阅


 

目录

文件修订记录...2

目录...3

1ARMv8存储管理...4

1.1Aarch64 Linux中的内存布局... 4

1.2AArch64的虚拟地址格式...4

1.2.14K页时的虚拟地址...4

1.2.264K页时的虚拟地址...5

2head.S页表建立过程分析...6

2.1页表建立函数__create_page_tables.6

2.1.1pgtbl       x25,x26, x24分析... 7

2.1.2MM_MMUFLAGS解释...8

2.1.3create_pgd_entry/create_block_map宏解释...8

3问题解答...12

3.1TLB打开之前,内存物理内存大小如何通知OS内核?...12

3.2PGD及PTE的填写过程...12

3.2.1map_mem()12

3.2.2create_mapping()12

3.2.3alloc_init_pud()13

3.2.4alloc_init_pmd()14

3.2.5set_pmd()15

3.2.6alloc_init_pte()15

3.2.7set_pte()15

3.3ARMv8三级页表情况下,全部把页表放到内存中是放不下的(1G大小),是不是部分放到硬盘中?...16

 

1 ARMv8存储管理

1.1 Aarch64 Linux中的内存布局

ARMv8架构可以支持48位虚拟地址,并配置成4级页表(4K页),或者3级页表(64K页)。而本Linux系统只使用39位虚拟地址(512G内核,512G用户),配置成3级页表(4K页)或者2级页表(64K页)

用户空间的地址63:39位都置零,内核空间地址63:39都置一,虚拟地址的第63位可以用来选择TTBRx。swapper_pg_dir只包含内核全局映射,用户的pgd包含用户(非全局)映射。swapper_pg_dir地址在TTBR1中,不会写入TTBR0中。

AArch64Linux内存布局:

Start                                 End                             Size                     Use

--------------------------------------------------------------------------------------------------

0000000000000000         0000007fffffffff      512GB          user

 

ffffff8000000000             ffffffbbfffcffff           ~240GB       vmalloc

 

ffffffbbfffd0000               ffffffbcfffdffff         64KB            [guardpage]

 

ffffffbbfffe0000               ffffffbcfffeffff         64KB            PCII/O space

 

ffffffbbffff0000               ffffffbcffffffff          64KB            [guard page]

 

ffffffbc00000000             ffffffbdffffffff       8GB               vmemmap

 

ffffffbe00000000             ffffffbffbffffff         ~8GB           [guard,future vmmemap]

 

ffffffbffc000000                     ffffffbfffffffff            64MB           modules

 

ffffffc000000000             ffffffffffffffff                  256GB          memory

1.2 AArch64的虚拟地址格式

1.2.1 4K页时的虚拟地址

 

1.2.2 64K页时的虚拟地址


 


2 head.S页表建立过程分析

2.1 页表建立函数__create_page_tables

该函数用于在内核启动时,为FDT(设备树)、内核镜像创建启动所必须的页表。等内核正常运行后,还需运行create_mapping为所有的物理内存创建页表,这将覆盖__create_page_tables所创建的页表。

内核开始运行时创建页表源文件:arm64/kernel/head.Sline345

/*

 * Setup the initial page tables. We only setup the barest amount which is

 * required to get the kernel running. The following sections are required:

 *   -identity mapping to enable the MMU (low address, TTBR0)

 *   -first few MB of the kernel linear mapping to jump to once the MMU has

 *    been enabled, including the FDT blob (TTBR1)

 */

__create_page_tables:

          pgtbl     x25, x26,x24                         //idmap_pg_dir and swapper_pg_dir addresses

 

          /*

           * 清空新建的两个页表TTBR0,TTBR1

           */

          mov       x0,x25

          add       x6,x26, #SWAPPER_DIR_SIZE

1:        stp       xzr,xzr, [x0], #16

          stp       xzr,xzr, [x0], #16

          stp       xzr,xzr, [x0], #16

          stp       xzr,xzr, [x0], #16

          cmp       x0,x6

          b.lo      1b

 

          ldr       x7,=MM_MMUFLAGS

 

          /*

           * Create the identity mapping.

           */

          add       x0, x25,#PAGE_SIZE                   // sectiontable address

          adr       x3, __turn_mmu_on            // virtual/physical address

          create_pgd_entry x25, x0, x3, x5, x6  //展开见1.1.3

          create_block_map x0, x7, x3, x5, x5, idmap=1

 

          /*

           * Map the kernel image (starting withPHYS_OFFSET).

           */

          add       x0,x26, #PAGE_SIZE                   //section table address

          mov       x5,#PAGE_OFFSET

          create_pgd_entry x26, x0, x5, x3, x6

          ldr       x6,=KERNEL_END - 1

          mov       x3,x24                               // physoffset

          create_block_map x0, x7, x3, x5, x6

 

          /*

           * Map the FDT blob (maximum 2MB; must bewithin 512MB of

           * PHYS_OFFSET).

           */

          mov       x3,x21                               // FDTphys address

          and       x3,x3, #~((1 << 21) - 1)    // 2MBaligned

          mov       x6,#PAGE_OFFSET

          sub       x5,x3, x24                           //subtract PHYS_OFFSET

          tst       x5,#~((1 << 29) - 1)                 //within 512MB?

          csel      x21,xzr, x21, ne            // zero the FDTpointer

          b.ne      1f

          add       x5,x5, x6                            // __va(FDTblob)

          add       x6,x5, #1 << 21             // 2MB forthe FDT blob

          sub       x6,x6, #1                            //inclusive range

          create_block_map x0, x7, x3, x5, x6

1:

          ret

ENDPROC(__create_page_tables)

 

 

2.1.1  pgtbl   x25, x26, x24分析

pgtbl是个宏,定义如下:

arm64/kernel/head.S line55

          .macro    pgtbl,ttb0, ttb1, phys

          add       \ttb1,\phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE

          sub       \ttb0,\ttb1, #IDMAP_DIR_SIZE

          .endm

pgtbl               x25,x26, x24  //展开后如下

add                x26,x24, #TEXT_OFFSET -SWAPPER_DIR_SIZE

sub                x25,x26,#IDMAP_DIR_SIZE

 

其中各变量定义如下:

#defineSWAPPER_DIR_SIZE     (3 * PAGE_SIZE)

#defineIDMAP_DIR_SIZE                (2 *PAGE_SIZE)

说明:

1、关于TTBR0、TTBR1的介绍见ARM ARM 手册的Page B4-1708

2、x25中存TTBR0(TTBR0 holds the base address of translation table 0)的地址;

3、X26存TTBR1(TTBR1 holds the base address of translation table 1)地址;

4、X24 存PHYS_OFFSET,/* PHYS_OFFSET- the physical address of the start of memory. */

    #definePHYS_OFFSET      ({ memstart_addr; })

5、TEXT_OFFSET是Bootloader启动时传进来的参数,是内核Image加载时相对于RAM起始地址的偏移量

6、PAGE_OFFSEST:the virtual address of the start of the kernel image.

 

 

 


图1  pgtbl宏分析

 

2.1.2 MM_MMUFLAGS解释

在文件arm64/kernel/head.S line71:

/*

 * Initial memory map attributes.

 */

#ifndefCONFIG_SMP

#definePTE_FLAGS      PTE_TYPE_PAGE | PTE_AF

#definePMD_FLAGS     PMD_TYPE_SECT | PMD_SECT_AF

#else

#definePTE_FLAGS      PTE_TYPE_PAGE | PTE_AF |PTE_SHARED

#definePMD_FLAGS     PMD_TYPE_SECT | PMD_SECT_AF| PMD_SECT_S

#endif

 

#ifdefCONFIG_ARM64_64K_PAGES

#defineMM_MMUFLAGS   PTE_ATTRINDX(MT_NORMAL) |PTE_FLAGS

#defineIO_MMUFLAGS      PTE_ATTRINDX(MT_DEVICE_nGnRE)| PTE_XN | PTE_FLAGS

#else

#defineMM_MMUFLAGS   PMD_ATTRINDX(MT_NORMAL) |PMD_FLAGS

#defineIO_MMUFLAGS      PMD_ATTRINDX(MT_DEVICE_nGnRE)| PMD_SECT_XN | PMD_FLAGS

#endif

 

根据以上宏定义能明确,MM_MMUFLAGS就是根据你编译内核时选定的页大小(64K or 4K),设置MMU。

2.1.3 create_pgd_entry/create_block_map宏解释

1、create_pgd_entry

/*

 * Macro to populate the PGD for thecorresponding block entry in the next

 * level (tbl) for the given virtual address.

 *

 * Preserves:     pgd,tbl, virt

 * Corrupts:       tmp1,tmp2

 */

      .macro   create_pgd_entry,pgd, tbl, virt, tmp1, tmp2

      lsr   \tmp1,\virt, #PGDIR_SHIFT

      and \tmp1,\tmp1, #PTRS_PER_PGD - 1    // PGD index

      orr  \tmp2,\tbl, #3                   // PGD entrytable type

      str   \tmp2,[\pgd, \tmp1, lsl #3]

      .endm

 

根据以上定义,create_pgd_entry x25, x0, x3, x5, x6展开后如下:

lsr   x5, x3,# PGDIR_SHIFT      //X3中存放的是__turn_mmu_on的地址,右移PGDIR_SHIFT(30)位

and  x5, x5, #PTRS_PER_PGD – 1//将<38:30>置位

orr  x6, x0, #3         //x0存放PGD entry(即下级页表地址),低三位用于表项的有效位

str  x6, [ x25, x5, lsl #3] //将entry存放到TTBR0(x25)中偏移为x5左移3位(乘8,因为entry为8byte)的位置处。

为了便于理解,如下图所示:


 

                                                                                                                          图2  4K页面时48位虚拟地址组成


注意:上图中虚拟地址对应的表格名称是:

PGD:全局描述符表

PUD:折合到PGD中,Linux中不使用

PMD:页表中间描述符表

PTE:页表

Linux内核只使用了39位虚拟地址


 

 

图3  64位页表项格式

 

 

 

 

图4

同理,create_pgd_entry x26, x0, x5, x3, x6展开后如下:

lsr   x3, x5,#PGDIR_SHIFT //X5中存放的是PAGE_OFFSET= 0xffffffc000000000,右移PGDIR_SHIFT位存入X3

and  x3, x3,#PTRS_PER_PGD – 1//将<38:30>置位

orr  x6, x0, #3       //x0存放TTBR1指向的页的下一页,低三位用于表项的有效位,存入x6

str  x6, [ x26, x3,lsl #3] //将entry存放到TTBR0(x25)中偏移为x5左移3位的位置处

以上内容就是,填写TTBR1指向的页表中偏移为x3*8(因为一个entry是8byte)的页表项,内容为x6(即图4中x0所指的位置)

 

 

2、create_block_map

/*

 * Macro to populate block entries in the pagetable for the start..end

 * virtual range (inclusive).

 *

 * Preserves:     tbl,flags

 * Corrupts:       phys,start, end, pstate

 */

      .macro   create_block_map,tbl, flags, phys, start, end, idmap=0

      lsr   \phys,\phys, #BLOCK_SHIFT

      .if   \idmap

      and \start,\phys, #PTRS_PER_PTE - 1 // table index

      .else

      lsr   \start,\start, #BLOCK_SHIFT

      and \start,\start, #PTRS_PER_PTE - 1 // table index

      .endif

      orr  \phys,\flags, \phys, lsl #BLOCK_SHIFT     //table entry

      .ifnc       \start,\end

      lsr   \end,\end, #BLOCK_SHIFT

      and \end,\end, #PTRS_PER_PTE - 1          // tableend index

      .endif

9999:    str   \phys,[\tbl, \start, lsl #3]         // storethe entry

      .ifnc       \start,\end                          //ifnc:如果string1!=string2

      add \start,\start, #1                  // next entry

      add \phys,\phys, #BLOCK_SIZE         // next block

      cmp       \start,\end

      b.ls 9999b

      .endif

      .endm

 

根据以上宏定义,create_block_map x0, x7, x3,x5, x5, idmap=1,翻译后如下:

lsr  x3, x3, # BLOCK_SHIFT

and  x5, x3 # PTRS_PER_PTE – 1

orr  x3, x7, x3, lsl  # BLOCK_SHIFT

9999:

      str x3, [x0, x5, lsl #3]

 

同理,create_block_map x0, x7, x3, x5,x6展开后如下:

      lsr   x3,x3, #BLOCK_SHIFT

      lsr   x5,x5, #BLOCK_SHIFT

      and x5,x5, #PTRS_PER_PTE - 1  // table index

      orr  x3,x7, x3, lsl #BLOCK_SHIFT     // tableentry

      lsr   x6,x6, #BLOCK_SHIFT

      and x6,x6, #PTRS_PER_PTE - 1         // table endindex

9999:    str   x3,[x0, x5, lsl #3]            // store the entry

      add x5,x5, #1                   // next entry

      add x3,x3, #BLOCK_SIZE            // next block

      cmp       x5, x6

      b.ls 9999b

create_block_mapx0, x7, x3, x5, x6宏的作用就是创建内核镜像所有的映射关系

     

     

3 问题解答

3.1  TLB打开之前,内存物理内存大小如何通知OS内核?

Bootloader通过设备树(devicetree.dts文件)将物理内存起始地址及大小传给Linux 内核。物理内存的大小需要在bootloader即dts文件中写明。dts文件中内存声明如下:

      memory {

             device_type= "memory";

             reg= <0x00000000 0x80000000>;

      };

Reg字段:<地址 大小>

以上声明一段内存:从地址0x开始,大小为2G

 

3.2 PGD及PTE的填写过程

内核初始化时,会调用map_mem对所有内存建立页表,进行映射,函数执行流程是:

start_kernel()àsetup_arch()àpaging_init()àmap_mem()àcreate_mapping()

下面我们从map_mem()函数开始分析。

 

3.2.1 map_mem()

arm64/mm/mmu.cline254

staticvoid __init map_mem(void)

{

      struct memblock_region *reg;

 

      // 按照内存块进行映射,映射所有内存bank

      for_each_memblock(memory, reg) {

             phys_addr_t start = reg->base;

             phys_addr_t end = start +reg->size;

             if (start >= end)  //如果end不大于start 则退出

                    break;

             create_mapping(start,__phys_to_virt(start), end - start);//创建映射

      }

}

3.2.2 create_mapping()

arm64/mm/mmu.cline 230

/*

 * Create the page directory entries and anynecessary page tables for the

 * mapping specified by 'md'.

 */

staticvoid __init create_mapping(phys_addr_t phys, unsigned long virt,

                             phys_addr_t size)

{

      unsigned long addr, length, end, next;

      pgd_t *pgd;

 

      if (virt < VMALLOC_START) {          //对虚拟地址进行检查

             pr_warning("BUG: not creatingmapping for 0x%016llx at 0x%016lx - outside kernel range\n",

                       phys, virt);

             return;

      }

 

      addr = virt & PAGE_MASK;  // PAGE_MASK=(~(PAGE_SIZE-1)),将虚拟地址的低位偏移掩掉

 

//计算需要映射的内存长度,对齐到下一页的边界

      length= PAGE_ALIGN(size + (virt & ~PAGE_MASK));

 

//一级数组中addr对应的段在init_mm->pgd的下标,即在内核的pgd中获得一个entry

      pgd = pgd_offset_k(addr);

      end = addr + length; //计算需要映射的结束地址

      do {

             next = pgd_addr_end(addr, end);//获得下一段开始地址

 

//申请并初始化一个段

//段码,虚拟地址,结束地址,物理地址,内存类型

             alloc_init_pud(pgd,addr, next, phys);

             phys += next - addr;//物理地址累加

      } while (pgd++, addr = next, addr != end);

}

3.2.3 alloc_init_pud()

arm64/mm/mmu.cline213

staticvoid __init alloc_init_pud(pgd_t *pgd, unsigned long addr,

                             unsigned long end, unsigned long phys)

{

//由于Linux内核不使用pud,所以pud折如pgd,这里的pud=pgd  

pud_t *pud = pud_offset(pgd, addr);

      unsigned long next;

 

      do {

             next = pud_addr_end(addr, end);

             alloc_init_pmd(pud, addr, next, phys);

             phys += next - addr;

      } while (pud++, addr = next, addr != end);

}

 

3.2.4 alloc_init_pmd()

arm64/mm/mmu.cline 187

staticvoid __init alloc_init_pmd(pud_t *pud, unsigned long addr,

                             unsigned long end, phys_addr_t phys)

{

      pmd_t *pmd;

      unsigned long next;

 

      /*

       *Check for initial section mappings in the pgd/pud and remove them.

       */

      if (pud_none(*pud) || pud_bad(*pud)) {

             pmd = early_alloc(PTRS_PER_PMD *sizeof(pmd_t));

             pud_populate(&init_mm, pud,pmd);

      }

      pmd = pmd_offset(pud, addr);

      do {

             next = pmd_addr_end(addr, end);

             /* try section mapping first */

//addr,end, phys都是段对齐,则直接进行段映射(大部分情况下应该是满足条件),否则需要进一步填写PTE

//段大小在不同页大小情况下不同,在3级页表时,2M;在2级页表时,512M

             if (((addr | next | phys) &~SECTION_MASK) == 0)

//将物理地址及一些段属性存放到pmd中

                    set_pmd(pmd, __pmd(phys |prot_sect_kernel));

             else

                    alloc_init_pte(pmd, addr, next,__phys_to_pfn(phys));

             phys += next - addr;

      } while (pmd++, addr = next, addr != end);

}

 

3.2.5 set_pmd()

arm64/include/asmline 195

staticinline void set_pmd(pmd_t *pmdp, pmd_t pmd)

{

      *pmdp = pmd;

      dsb();//同步数据进RAM(由于有cache机制,所以数据操作的时候是先保存在cache中的,这里是强制将数据从cache中刷进RAM中)

}

3.2.6 alloc_init_pte()

arm64/mm/mmu.cline 169

staticvoid __init alloc_init_pte(pmd_t *pmd, unsigned long addr,

                             unsigned long end, unsigned long pfn)

{

      pte_t *pte;

 

      if (pmd_none(*pmd)) {

             pte = early_alloc(PTRS_PER_PTE *sizeof(pte_t));

             __pmd_populate(pmd, __pa(pte),PMD_TYPE_TABLE);

      }

      BUG_ON(pmd_bad(*pmd));

 

      pte = pte_offset_kernel(pmd, addr);

      do {

             set_pte(pte,pfn_pte(pfn, PAGE_KERNEL_EXEC));

             pfn++;

      } while (pte++, addr += PAGE_SIZE, addr !=end);

}

3.2.7 set_pte()

arm64/include/asm/pgtable.hline 150

staticinline void set_pte(pte_t *ptep, pte_t pte)

{

      *ptep = pte;

}

3.3 ARMv8三级页表情况下,全部把页表放到内存中是放不下的(1G大小),是不是部分放到硬盘中?

答:ARMv8 OS是根据内存大小建立页表的,例如当物理内存只有1G时,1G=230=218 *4K(页大小),即需要218个PTE,每个页表512个PTE,所以需要29个PT表,共需要29*4K=2M大小的页表(事实上还需要计算PGD和PMD,各4K)。

所以1G内存空间,需要2M大小页表;

2G——4M

100G——200M

512G——1G页表

相对内存大小来说,页表大小还是很小的。

注意:如果是64位机器,就不存在高端内存一说,因为地址空间很大很大,属于内核的空间也不止1G,在aarch64 linux中内核空间是512G,内核完全可以直接管理所有内存。

 

 

 

# 学习对象在全民造车、造芯的大时代,在努力去解决卡脖子的时代,ASIC硬件、SOC底层软件、Linux Kernel等操作系统软件(内核/驱动)、软硬件方面的系统架构师等的岗位需求也越来越明显,社会一直都是非常缺人的,缺的是核心的那一小撮、领头的那一小撮,社会所缺的更是能够软硬件融合的那一小撮人……总之,要想在这个时代,站稳自己的脚跟,能够在大公司或行业上拥有一席之地,就必需深入学习底层技术原理,核心技术才是您的看家本领。本课程设计之初,主要针对SOC底层软件开发的者、系统开发者,或者励志成为这样的人。既适合资深/高级工程师来查缺补漏,又适合初级工程师入门。(理论上该课程和ASIC硬件电路设计无关,该课程偏软件,但事实购买该课程的做ASIC的同学已然超过了15%)适用人群1、芯片开发者(包括底层软件、或做ASIC硬件的)。不限行业,例如车、云、物联网、移动端等领域;2、汽车行业开发者(主机厂、tier1、SOC厂家、各级供应商);3、嵌入式开发者、kernel开发者、驱动、软件工程师;4、学生。既适合学生从入门到精通,也适合资深工程师查缺补漏;您的收益:1、全体系的掌握ARMv8/ARMv9的核心知识点(ARM基础、异常中断GIC、MMU/Cache、architecture...);2、掌握ARM架构、掌握SOC架构、掌握常规IP(gic、smmu、timer、AXI/ACE/CHI、TZC400...);3、快速熟悉常规系统软件(bootrom、spl、ATF、TEE、bootloader、kernel...), Secureboot安全启动...4、技术水平提升N个level, 掌握快速的学习方法;# 学习什么在ARM蓬勃发展的年代,不仅仅涉及到物联网IOT、移动领域(如手机)、汽车电子领域,现在还涉及到PC、服务器的,简直就是各行各业。ARMv8出来已经有10年了,ARMv9也2年时间了。在技术不断更新迭代的背景下,此时再去学习十五年前的ARMv7、二十年前的ARMv5/v6显然不是明智的选择。本课程主要基于当前最新的架构,ARMv8aarch64ARMv9,如涉及具体的ARM Core IP主要还是以最新的ARM Core IP为主,软件架构也是以当前最主流的/未来所趋势的架构来讲解。以下也给大家列举初了一个ARM产品的timeline的总结(在本课程中有着大量的这种总结),从这张图中,您是可以清晰的看到本课程拥有独具一格的风格、拥有全网最新(且唯一)的资料总结或学习路线。# 本课程大纲和规划(课程持续更新中,课程总量统计:2022/10/02  当前是 61节课, 22小时)第一章:主要是快速学习: ARM简介、指令集、寄存器总结等。第二章:本系列视频的一大亮点,系统全面地讲解了arm异常中断gic等相关的软硬件知识,本人一直在倡导“学arm安全其实就是学arm架构,学arm架构其实就是学习arm的异常和中断”,异常中断是领着你进入架构的入门,是让你变成系统软硬件架构师的必走之路。第三章:安全专题,这也是本视频最核心的东西。因为你无论买书还是看博客等,你都很难找到讲解安全的教程,这里就是有和无的区别。本人系统的整理的安全的知识,带领你快速入门。第四章:mmu专题,透过事务看本质的讲解,白话式的演讲。在所有模块中,mmu也算是相对较简单模块。相信人人听得懂,人人学得会。第五章:cache专题,一切追求实事求是,不人云亦云,一切知识点都有迹可循,推翻了网络的很多观念。在众多模块中,cache算是一个比较难的模块。了解了cache后,才能算真正了解系统的软硬件架构。第六章:虚拟化,本人不擅长,会啥就随便讲点啥。(以后学会了再来补)第七章:architecture,就是零散和零碎的系统架构知识,如exclusive、arch timer、reset、系统启动、SOC设计、AMBA/AXI/ACE、DSU、WFE/WFI这样的。第八章: 新增的ARMv9 CCA/RME安全架构专题第九章:主要放置一些直播课。# 课程收益1、知道我学习什么,我要怎么去学习,从此之后有了一个明确的学习路线。2、认识一些共同目标的人,相互讨论问题,共同进步。勤学、共学、助学。3、ARM不再神秘,SOC不在神秘,让您短期内就能cover住全局4、熟悉ARM Architecture架构知识5、熟悉SOC架构知识6、熟悉主流的系统软件框架7、熟悉各项硬件原理和机制,如异常中断、MMU、cache、TLB、VMSA、Trustzone6、深入了解当前的系统架构、软硬件架构,能够看懂这些大家,将来也能够自己设计。7、熟悉系统的启动流程、Secureboot等8、熟悉各类标准和规范9、能够进入芯片厂商干活、能够在非芯片产生成为技术担当。10、学习资料的获取方法,会看11500多页的ARM手册,会看数以百计的ARM各项参考手册。 本课程会持续更新。也希望通过本课程的学习,能够让大家的ARMv8/ARMv9开发技术能有质的飞越,能找到自己心仪的工作。在购买之前,也建议大家看一看第一章第一节的课程介绍。
LinuxARMv8-A架构下使用长描述符格式处理页面错误(page fault)。 ARMv8-A架构引入了长描述符格式,这是一种改进的内存管理单元(MMU)设计,它提供了更灵活、更高效的地址转换和页面错误处理能力。 当发生页面错误时,例如访问一个没有映射的地址或试图访问一个只读内存区域进行写操作时,ARMv8-A的MMU会捕获这个错误并触发一个页面错误异常。 在长描述符格式下,页面错误有两种类型:同步页面错误和异步页面错误。同步页面错误是指对当前指令引起的页面错误,异常处理程序会被同步地执行。异步页面错误是指对其他指令引起的页面错误,异常处理程序可能会在以后的时间点执行。 对于页面错误的处理,Linux内核会在异常处理程序中根据错误类型采取相应的措施。通常,处理程序会检查错误类型和描述符类型,然后根据情况更新页表项或者触发进一步的异常处理流程。 ARMv8-A的长描述符格式提供了更多的页表项信息,例如权限设置、虚拟地址映射等,这使得页面错误的处理更加灵活和细粒度。此外,ARMv8-A还支持虚拟化技术,可以在虚拟机监视器和虚拟机之间进行页面错误的处理和隔离。 总的来说,LinuxARMv8-A架构下使用长描述符格式处理页面错误,通过异常处理程序和改进的页表项结构,可以更加有效地处理和隔离页面错误,提升系统的可靠性和性能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值