|
|
|
@ -145,11 +145,11 @@ clobbered_regs(破坏描述部分)
|
|
|
|
|
|
|
|
|
|
**汇编代码模板**:汇编语句模板由汇编语句序列组成,语句之间使用“;”、“\n”或“\n\t”分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0,%1…,%9。指令中使用上述占位符表示的操作数,占位符从%0起,依次表示输出操作数、输入操作数。
|
|
|
|
|
|
|
|
|
|
**输出部分:**描述输出操作数,可以有多个约束,不同的操作数描述符之间用逗号格开,每个约束用“=”开头,接着用字母表示操作数的类型。常用约束有:"=r",表示相应操作数可以使用一个通用寄存器,"=m",表示操作数存放在内存单元中。例如:"=m" (ret),在这里的ret是最终存放输出结果的C程序变量,而“=m”则是限定字符串,限定字符串表示了对它之后的变量的限制条件,这样GCC就可以根据这些条件决定如何分配寄存器,如何产生必要的代码处理指令,以及如何处理操作数与C表达式或C变量之间的关系。“=”后面所跟的字母以及含义见表1.2。
|
|
|
|
|
**输出部分**:描述输出操作数,可以有多个约束,不同的操作数描述符之间用逗号格开,每个约束用“=”开头,接着用字母表示操作数的类型。常用约束有:"=r",表示相应操作数可以使用一个通用寄存器,"=m",表示操作数存放在内存单元中。例如:"=m" (ret),在这里的ret是最终存放输出结果的C程序变量,而“=m”则是限定字符串,限定字符串表示了对它之后的变量的限制条件,这样GCC就可以根据这些条件决定如何分配寄存器,如何产生必要的代码处理指令,以及如何处理操作数与C表达式或C变量之间的关系。“=”后面所跟的字母以及含义见表1.2。
|
|
|
|
|
|
|
|
|
|
**输入部分:**输入部分与输出部分相似,但是没有“=”符号。
|
|
|
|
|
**输入部分**:输入部分与输出部分相似,但是没有“=”符号。
|
|
|
|
|
|
|
|
|
|
**破坏描述部分:**破坏描述符用于通知编译器我们使用了哪些寄存器或内存, 可以防止内嵌汇编在使用某些寄存器时导致错误。修改描述符是由逗号隔开的字符串组成的,每个字符串描述一种情况,一般是寄存器,有时也会有“memory”。具体的意思就是告诉编译器在编译内嵌汇编的时候不能使用某个寄存器或者不能使用内存的空间。
|
|
|
|
|
**破坏描述部分**:破坏描述符用于通知编译器我们使用了哪些寄存器或内存, 可以防止内嵌汇编在使用某些寄存器时导致错误。修改描述符是由逗号隔开的字符串组成的,每个字符串描述一种情况,一般是寄存器,有时也会有“memory”。具体的意思就是告诉编译器在编译内嵌汇编的时候不能使用某个寄存器或者不能使用内存的空间。
|
|
|
|
|
|
|
|
|
|
表1.2 内联汇编常用约束
|
|
|
|
|
|
|
|
|
@ -632,7 +632,7 @@ csrw medeleg, 1<<0 | 1<< 3 | 1<<8 | 1<<12 | 1<<13 | 1<<15
|
|
|
|
|
|
|
|
|
|
地址变换机构首先获得逻辑地址va的VPN[2],在页目录的根目录(根目录的地址由satp寄存器保存)中查找对应的PDE,依此得知以及页目录的PPN;进而找到页目录实际存储的基础物理页,再根据逻辑地址中的VPN[1]取得页目录内对应的PDE;接着找到页表实际存储的基础物理页,再根据逻辑地址中的VPN[0]取得页表内的PTE,最后获得给定虚拟地址的物理地址对应的PPN,再将PPN和虚拟地址中的page offset进行移位相加,最终得到物理地址pa。
|
|
|
|
|
|
|
|
|
|
**需要注意的是,图1.8中所示的地址变换过程是由RISC-V处理器硬件完成的,但是页表的构造却是操作系统完成的!**对于系统中运行的每个进程(操作系统本身也可以看作是一个特殊的进程),都应该有个一页表与其对应,当处理器需要执行某个进程时,就应该将satp指向想要执行的进程。另外,对于一个进程而言(例如我们的hello world程序),它可能用不满全部虚拟地址空间(Sv39的虚拟地址空间高达512GB!),这种情况下它的页表中可能只有非常少部分的PDE/PTE是有效的(V位为1),而其他PDE/PTE并不指向任何物理内存页面。
|
|
|
|
|
**需要注意的是,图1.8中所示的地址变换过程是由RISC-V处理器硬件完成的,但是页表的构造却是操作系统完成的**!对于系统中运行的每个进程(操作系统本身也可以看作是一个特殊的进程),都应该有个一页表与其对应,当处理器需要执行某个进程时,就应该将satp指向想要执行的进程。另外,对于一个进程而言(例如我们的hello world程序),它可能用不满全部虚拟地址空间(Sv39的虚拟地址空间高达512GB!),这种情况下它的页表中可能只有非常少部分的PDE/PTE是有效的(V位为1),而其他PDE/PTE并不指向任何物理内存页面。
|
|
|
|
|
|
|
|
|
|
将一个进程的(部分)地址空间“共享”给另一个进程,是操作系统中的常规操作,例如将操作系统本身的地址空间部分开放给某用户进程。有了页表的帮助,这种共享也非常便捷,例如我们可以把某用户进程的PDE指向操作系统的PD或PT。但是,这种共享必须考虑到权限问题!例如,将用户进程的PDE或PTE中的权限位进行相应的设置,避免对操作系统代码可能的破坏(如不允许写或执行)。由于页面权限的限制,用户进程的执行可能会碰到访存方面的exception,如访问某个V=0的页面(缺页异常),或者执行X=0的页中的代码,这些exception都会导致当前程序的中断,并进入更高特权级(如PKE操作系统运行的S模式)中处理。
|
|
|
|
|
|
|
|
|
|