loongarch架构介绍(三)—地址翻译

系统 OpenHarmony
本文介绍了地址翻译模式以及相关的配置。下一篇文章将继续对loongarch虚拟内存系统中的其他部分。

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

前言

本文是loongarch架构介绍系列的第三篇文章。前面的第一篇文章介绍了loongarch架构中的基础指令和使用,第二篇文章介绍了内存模型、原子指令与栅障指令的使用。

虚拟内存系统是软硬协同的一个经典案例,如今主流的架构和操作系统都已经支持虚拟内存机制。本文介绍loongarch虚拟内存系统中的地址翻译部分,主要包括地址翻译模式、loongarch中多级页表和相关的配置。另外本文中许多寄存器等资源属于特权资源,因此也会介绍loongarch中的csr特权指令和特权级作为背景知识。

一、特权级和csr特权指令

虚拟内存相关的寄存器等资源属于特权资源,因此在介绍loongarch虚拟内存相关机制之前,先对loongarch中的特权指令和特权级进行介绍。

1、特权级

loongarch架构中有4个特权等级(Privilege Level,简称PLV),分别为PLV0-PLV3。其中PLV0的权限最高,也是唯一可以使用特权指令并访问所有特权资源的特权等级。而PLV3的权限最低。并且PLV1-PLV3这三个特权级下大部分情况下都不能执行特权执行以访问特权资源。

例如,在Linux系统loongarch架构相关代码中,内核态处于PLV0,而用户态处于PLV3。

loongarch架构中有许多控制状态寄存器(CSR),在loongarch资料中一般用CSR.xxx来表示某个控制状态寄存器。cpu当前所处的特权级就由当前模式信息寄存器CSR.CRMD中的PLV域确定,即通过配置CSR.CRMD.PLV可以设置当前特权级。

2、csr特权指令

csr特权指令用于访问和配置控制状态寄存器,有以下几种:

csrrd:读取CSR。如csrrd rd, csr_num表示将csr_num对应的CSR的值写入到通用寄存器rd中。其中csr_num为loongarch中控制状态寄存器的编号,如CSR.CRMD对应的编号为0。

如下面代码将CSR.CRMD中值读到临时寄存器t0中:

csrrd t0, 0 // CSR.CRMD对应的编号为0

csrwr:写入CSR。如csrwr rd, csr_num表示将通用寄存器rd中的值写入csr_num对应的CSR,同时将csr_num对应CSR中的旧值返回到rd中。

如使用下面代码可以设置特权级为PLV3:

li.d t0, 0xXXXXXXXXXXXXXXX3 // 最低两位为3
csrwr t0, 0

csrxchg:如csrxchg rd, rj, csr_num表示将通用寄存器rj中的值作为掩码mask,将rd中值写入到csr_num对应CSR中对应掩码为1的那些比特,该CSR中的其余比特不变。同时将csr_num对应CSR中的旧值返回到rd中。

如以下代码同样可以设置特权级为PLV3:

li.d t0, 0x3
csrxchg t0, t0, 0 // 只将CSR.CRMD最后两位置1

下图为CSR.CRMD表中PLV部分描述:

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

二、地址空间

loongarch中的虚拟地址空间大小为:

  • LA32中虚拟地址空间大小为2^{32}232字节
  • LA64中虚拟地址空间大小为2^{64}264字节

loongarch中的物理地址空间大小为2^{PALEN}2PALEN字节,其中:

  • LA32中,PALEN为一个不超过36的正整数,通常为32
  • LA64中,PALEN为一个不超过60的正整数
  • PALEN由具体的实现决定,软件可以通过CPUCFG指令读取PALEN的值

三、地址翻译模式

loongarch虚实地址转换机制首先由其地址翻译模式所确定。

loongarch中有两种地址翻译模式:

直接地址翻译模式:在该模式下,物理地址直接等于虚拟地址的低PALEN位,不足补0。相当于没有进行映射。

映射地址翻译模式:在该模式下,又分为两种模式:

  • 直接映射地址翻译模式(简称直接映射模式):相当于线性映射。具体细节见后文中说明。
  • 页表映射地址翻译模式(简称页表映射模式):相当于分页机制。具体细节见后文中说明。

其中,直接地址翻译模式和映射地址翻译模式不能够同时启用。但在映射地址翻译模式下,可以同时启用直接映射模式和页表映射模式,进行地址翻译时,会优先使用直接映射模式,如果无法使用直接映射模式,才会使用页表映射模式进行翻译。

1、地址翻译模式的配置

loongarch中通过控制寄存器CSR.CRMD配置地址翻译模式:

  • CSR.CRMD中DA=1且PG=0:直接地址翻译模式
  • CSR.CRMD中DA=0且PG=1:映射地址翻译模式
  • 其他DA和PG值的组合的行为未定义

CSR.CRMD表中DA和PG部分如下图:

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

类似于上文中特权级的设置,地址翻译模式的设置同样使用csrwr等指令。

2、直接映射模式及其配置

loongarch中的直接映射模式是一种线性的映射方式,有点类似于分段。loongarch中通过配置直接映射配置窗口寄存器,来配置直接映射。

共有4个直接映射配置窗口寄存器,CSR.DMW0-CSR.DMW3,配置一个窗口相当于映射一段内存区域。其中CSR.DMW0和CSR.DMW1映射的内存区域可以同时用于取指和load/store操作,而CSR.DMW2和CSR.DMW3映射的内存区域仅用于load/store操作。

下面对直接映射模式配置和映射规则进行说明。

(1) LA32

下面以LA32、且PALEN=32为例进行说明。

LA32中直接映射配置窗口寄存器内容如下图:

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

其中:

  • PLV0等域为使能CSR.DMW寄存器,且与访问特权级相关
  • MAT域与内存一致性模型和内存访问类型相关,可参考上一篇文章
  • PSEG域为配置的物理地址最高3位
  • VSEG域为配置的虚拟地址最高3位

例如,以下代码配置CSR.DMW0,将虚拟地址0x80000000-0x9fffffff映射到物理地址0x0-0x1fffffff:

li.w t0, 0x80000011
csrwr t0, 0x180 // 0x180对应CSR.DMW0

解释如下:

  • 0x80000011中,VSEG为0b100,表示匹配的虚拟地址的最高3位为0b100,即虚拟地址0x80000000-0x9fffffff
  • 0x80000011中,PSEG为0b0,表示匹配的物理地址的最高3位为0b0,即对应物理地址0x0-0x1fffffff

(2)LA64

下面以LA64、且PALEN=48为例进行说明。

LA64中直接映射配置窗口寄存器内容如下图:

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

其中:

  • PLV0等域、MAT域与LA32中作用相同
  • VSEG域与LA32中类似,但是有4位

例如,以下代码配置CSR.DMW0,将虚拟地址0x9000000000000000-0x9000ffffffffffff映射到物理地址0x0-0xffffffffffff:

li.d t0, 0x9000000000000011
csrwr t0, 0x180 // 0x180对应CSR.DMW0

解释如下:

  • 0x9000000000000011中,VSEG为0x9,表示匹配的虚拟地址的最高4位为0x9,即虚拟地址0x9000000000000000-0x9000ffffffffffff
  • PALEN=48,对应的物理地址为整个2^{48}248大小的地址范围,即0x0-0xffffffffffff

3、页表映射模式及其配置

(1)页表基址

在开启页表映射模式之后,首先需要配置页表基址。

loongarch中可以同时有两个pgd(页全局目录)基址,地址分别存储于寄存器CSR.PGDL(低半地址空间全局目录基址)和CSR.PGDH(高半地址空间全局目录基址),分别对应低半地址空间和高半地址空间。CSR.PGDL和CSR.PGDH如下图:

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

上图中,GRLEN表示寄存器长度,VALEN表示虚拟地址长度。LA32中GRLEN为32,VALEN为32;LA64中GRLEN为64,VALEN为64。

低半地址空间和高半地址空间实际上就是对虚拟地址空间对半分成了两个部分。虚拟地址最高位为0则表示处于低半地址空间;为1则表示处于高半地址空间。两个部分的地址都用对应部分的pgd进行地址转换,互不干扰。

在Linux中,CSR.PGDH存放内核进程的pgd,CSR.PGDL中存放用户进程的pgd。loongarch中相当于在硬件上又对内核空间和用户空间的页表进行了隔离。

(2)页表分级

loongarch中可以自定义页表的分级,使用页表前需要配置页表分级。

loongarch中页表的具体分级由寄存器CSR.PWCL和CSR.PWCH决定,这两个寄存器分别控制低半部分和高半部分的页表分级,其中CSR.PWCH只存在于LA64。注:这里的低半部分和高半部分指的是寄存器分成了两部分。CSR.PWCL和CSR.PWCH分别如下图:

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

下图是一个多级页表的示例:

# loongarch架构介绍#[三]地址翻译-开源基础软件社区

解释如下:

其中xxbase表示该级在虚拟地址中的起始位置,xxwidth表示该级在虚拟地址中的长度

以LA64为例,配置Dir4_base、PTbase等域和Dir4_width、PTwidth等域,相当于指定了虚拟地址按分级页表规则的解析方式

虚拟地址的解析过程示例如下:

  1. 首先根据最高位选择CSR.PGDH或CSR.PGDL中的pgd,即目录4的基址
  2. 将虚拟地址中Dir4_base和Dir4_width指定范围的值作为索引,在目录4查找对应目录3的基址
  3. 将虚拟地址中Dir3_base和Dir3_width指定范围的值作为索引,在目录3查找对应目录2的基址
  4. 将虚拟地址中Dir2_base和Dir2_width指定范围的值作为索引,在目录2查找对应目录1的基址
  5. 将虚拟地址中Dir1_base和Dir1_width指定范围的值作为索引,在目录1查找对应末级页表的基址
  6. 将虚拟地址中PTbase和PTwidth指定范围的值作为索引,在末级页表中查找最终页表项

其中具体页表项相关信息见后续文章。

(3)配置

本小节以Linux源码中loongarch下页表基址和分级的配置进行分析。

代码如下:

static void setup_ptwalker(void)
{
unsigned long pwctl0, pwctl1;
unsigned long pgd_i = 0, pgd_w = 0; // Dir3_base和Dir3_width
unsigned long pud_i = 0, pud_w = 0; // Dir2_base和Dir2_width
unsigned long pmd_i = 0, pmd_w = 0; // Dir1_base和Dir1_width
unsigned long pte_i = 0, pte_w = 0; // PTbase和PTwidth
// PTEWidth为0,表示每个表项为64bit
// Dir4_base和Dir4_width未设置
pgd_i = PGDIR_SHIFT;
pgd_w = PAGE_SHIFT - 3;
#if CONFIG_PGTABLE_LEVELS > 3
pud_i = PUD_SHIFT;
pud_w = PAGE_SHIFT - 3;
#endif
#if CONFIG_PGTABLE_LEVELS > 2
pmd_i = PMD_SHIFT;
pmd_w = PAGE_SHIFT - 3;
#endif
pte_i = PAGE_SHIFT;
pte_w = PAGE_SHIFT - 3;
pwctl0 = pte_i | pte_w << 5 | pmd_i << 10 | pmd_w << 15 |
pud_i << 20 | pud_w << 25;
pwctl1 = pgd_i | pgd_w << 6;
// 设置CSR.PWCL和CSR.PWCH,LOONGARCH_CSR_PWCTL0为CSR.PWCL
// LOONGARCH_CSR_PWCTL1为CSR.PWCH
csr_write64(pwctl0, LOONGARCH_CSR_PWCTL0);
csr_write64(pwctl1, LOONGARCH_CSR_PWCTL1);
// 设置CSR.PGDL和CSR.PGDH
// CSR.PGDH中swapper_pg_dir为内核空间pgd
// CSR.PGDL为用户空间pgd,暂时设置为invalid_pg_dir,到进程创建等操作时分配
csr_write64((long)swapper_pg_dir, LOONGARCH_CSR_PGDH);
csr_write64((long)invalid_pg_dir, LOONGARCH_CSR_PGDL);
...
}

总结

本文介绍了地址翻译模式以及相关的配置。下一篇文章将继续对loongarch虚拟内存系统中的其他部分。

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

责任编辑:jianghua 来源: 51CTO 开源基础软件社区
相关推荐

2023-03-01 14:59:08

TLB维护架构

2022-12-15 17:31:41

架构龙芯

2023-02-21 16:46:04

loongarch架构

2023-01-04 15:20:51

loongarch架构

2022-10-08 11:16:04

UbuntuLoongArch

2011-07-11 15:20:15

MAC地址java

2010-05-13 09:01:05

Subversion下

2011-07-15 16:26:09

架构设计

2009-06-04 20:41:27

Eclipse插件介绍Eclipse插件下载

2022-03-10 11:57:16

ARMv8-AMMU程序

2013-07-15 16:18:08

2010-02-01 16:54:18

C++打印地址信息

2012-12-10 09:24:04

2010-08-13 09:13:56

CISCO路由器MAC地址

2012-11-27 12:02:20

路由器IPARP

2009-09-15 09:39:38

LINQ查询架构

2010-06-02 13:53:26

IPv6地址

2023-09-03 16:41:07

2010-01-08 11:05:49

Ubuntu常用软件

2010-03-03 13:56:24

点赞
收藏

51CTO技术栈公众号