pull/1/head
Zhiyuan Shao 3 years ago
parent c06fc5cef5
commit e3d592e001

@ -1,169 +1,316 @@
# 第二章.实验环境的安装与使用 # 第二章.实验环境的安装与使用
### 目录 ### 目录
- [2.1 头歌平台](#educoder) - [2.1 头歌平台](#educoder)
- [2.2 Ubuntu环境](#ubuntu) - [2.2 Ubuntu操作系统的配置](#ubuntu)
- [2.3 openEuler操作系统](#openeuler) - [2.3 openEuler操作系统配置](#openeuler)
- [2.4 riscv-pke实验代码的获取](#preparecode)
<a name="educoder"></a>
## 2.1 头歌平台
<a name="educoder"></a>
PKE实验在[头歌平台](https://www.educoder.net/)上进行了部署但因为仍在测试阶段所以没有开放全局选课感兴趣的读者可以尝试邀请码2T8MA。PKE实验2.0版本将于2021年秋季在头歌平台重新上线届时将开放全局选课。
## 2.1 头歌平台
<img src="pictures/fig2_install_1.png" alt="fig2_install_1" style="zoom:80%;" />
PKE实验在[头歌平台](https://www.educoder.net/)上进行了部署但因为仍在测试阶段所以没有开放全局选课感兴趣的读者可以尝试邀请码2T8MA。PKE实验2.0版本将于2021年秋季在头歌平台重新上线届时将开放全局选课。
图1.1 头歌课程界面。
<img src="pictures/fig2_install_1.png" alt="fig2_install_1" style="zoom:80%;" />
头歌平台为每个选课的学生提供了一个docker虚拟机该虚拟机环境中已经配置好了所有开发套件包括交叉编译器、Spike模拟器等用户可以通过shell选项*详细使用方法将待2.0上线时更新*进入该docker环境在该docker环境中完成实验任务。
图1.1 头歌课程界面。
<a name="ubuntu"></a> 头歌平台为每个选课的学生提供了一个docker虚拟机该虚拟机环境中已经配置好了所有开发套件包括交叉编译器、Spike模拟器等用户可以通过shell选项*详细使用方法将待2.0上线时更新*进入该docker环境在该docker环境中完成实验任务。
## 2.2 Ubuntu环境
实验环境我们推荐采用Ubuntu 16.04LTS或18.04LTSx86_64操作系统我们未在其他系统如archRHEL等上做过测试但理论上只要将实验中所涉及到的安装包替换成其他系统中的等效软件包就可完成同样效果。另外我们在EduCoder实验平台网址https://www.educoder.net 上创建了本书的同步课程课程的终端环境中已完成实验所需软件工具的安装所以如果读者是在EduCoder平台上选择的本课程则可跳过本节的实验环境搭建过程直接进入通过终端命令行进入实验环境。
<a name="ubuntu"></a>
PKE实验涉及到的软件工具有RISC-V交叉编译器、spike模拟器以及PKE源代码三个部分。假设读者拥有了Ubuntu 16.04LTS或18.04LTSx86_64操作系统的环境以下分别介绍这三个部分的安装以及安装后的检验过程。需要说明的是为了避免耗时耗资源的构建build过程一个可能的方案是从https://toolchains.bootlin.com 下载,**但是要注意一些依赖包如GCC的版本号**。
## 2.2 Ubuntu环境
**我们强烈建议读者在新装环境中完整构建buildRISC-V交叉编译器以及spike模拟器**。如果强调环境的可移植性,可以考虑在虚拟机中安装完整系统和环境,之后将虚拟机进行克隆和迁移。
实验环境我们推荐采用Ubuntu 16.04LTS或18.04LTSx86_64操作系统我们未在其他系统如archRHEL等上做过测试但理论上只要将实验中所涉及到的安装包替换成其他系统中的等效软件包就可完成同样效果。另外我们在EduCoder实验平台网址https://www.educoder.net 上创建了本书的同步课程课程的终端环境中已完成实验所需软件工具的安装所以如果读者是在EduCoder平台上选择的本课程则可跳过本节的实验环境搭建过程直接进入通过终端命令行进入实验环境。
### 2.1.1 RISC-V交叉编译器
PKE实验涉及到的软件工具有RISC-V交叉编译器、spike模拟器以及PKE源代码三个部分。假设读者拥有了Ubuntu 16.04LTS或18.04LTSx86_64操作系统的环境以下分别介绍这三个部分的安装以及安装后的检验过程。需要说明的是为了避免耗时耗资源的构建build过程一个可能的方案是从https://toolchains.bootlin.com 下载,**但是要注意一些依赖包如GCC的版本号**。
RISC-V交叉编译器是与Linux自带的GCC编译器类似的一套工具软件集合不同的是x86_64平台上Linux自带的GCC编译器会将源代码编译、链接成为适合在x86_64平台上运行的二进制代码称为native code而RISC-V交叉编译器则会将源代码编译、链接成为在RISC-V平台上运行的代码。后者RISC-V交叉编译器生成的二进制代码是无法在x86_64平台即x86_64架构的Ubuntu环境下直接运行的它的运行需要模拟器我们采用的spike的支持。
**我们强烈建议读者在新装环境中完整构建buildRISC-V交叉编译器以及spike模拟器**。如果强调环境的可移植性,可以考虑在虚拟机中安装完整系统和环境,之后将虚拟机进行克隆和迁移。
一般情况下我们称x86_64架构的Ubuntu环境为host而在host上执行spike后所虚拟出来的RISC-V环境则被称为target。RISC-V交叉编译器的构建build、安装过程如下
### 2.1.1 RISC-V交叉编译器
● 第一步,安装依赖库
RISC-V交叉编译器是与Linux自带的GCC编译器类似的一套工具软件集合不同的是x86_64平台上Linux自带的GCC编译器会将源代码编译、链接成为适合在x86_64平台上运行的二进制代码称为native code而RISC-V交叉编译器则会将源代码编译、链接成为在RISC-V平台上运行的代码。后者RISC-V交叉编译器生成的二进制代码是无法在x86_64平台即x86_64架构的Ubuntu环境下直接运行的它的运行需要模拟器我们采用的spike的支持。
RISC-V交叉编译器的构建需要一些本地支撑软件包可使用以下命令安装
一般情况下我们称x86_64架构的Ubuntu环境为host而在host上执行spike后所虚拟出来的RISC-V环境则被称为target。RISC-V交叉编译器的构建build、安装过程如下
`$ sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev device-tree-compiler`
● 第一步,安装依赖库
● 第二步获取RISC-V交叉编译器的源代码
RISC-V交叉编译器的构建需要一些本地支撑软件包可使用以下命令安装
有两种方式获得RISC-V交叉编译器的源代码一种是通过源代码仓库获取使用以下命令
`$ sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev device-tree-compiler`
`$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain.git`
● 第二步获取RISC-V交叉编译器的源代码
但由于RISC-V交叉编译器的仓库包含了Qemu模拟器的代码下载后的目录占用的磁盘空间大小约为4.8GB,(从国内下载)整体下载所需的时间较长。为了方便国内用户,我们提供了另一种方式就是通过百度云盘获取源代码压缩包,链接和提取码如下:
有两种方式获得RISC-V交叉编译器的源代码一种是通过源代码仓库获取使用以下命令
`链接: https://pan.baidu.com/s/1cMGt0zWhRidnw7vNUGcZhg 提取码: qbjh`
`$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain.git`
从百度云盘下载RISCV-packages/riscv-gnu-toolchain-clean.tar.gz文件大小为2.7GB再在Ubuntu环境下解压这个.tar.gz文件采用如下命令行
但由于RISC-V交叉编译器的仓库包含了Qemu模拟器的代码下载后的目录占用的磁盘空间大小约为4.8GB,(从国内下载)整体下载所需的时间较长。为了方便国内用户,我们提供了另一种方式就是通过百度云盘获取源代码压缩包,链接和提取码如下:
`$ tar xf riscv-gnu-toolchain-clean.tar.gz`
`链接: https://pan.baidu.com/s/1cMGt0zWhRidnw7vNUGcZhg 提取码: qbjh`
之后就能够看到和进入当前目录下的riscv-gnu-toolchain文件夹了。
从百度云盘下载RISCV-packages/riscv-gnu-toolchain-clean.tar.gz文件大小为2.7GB再在Ubuntu环境下解压这个.tar.gz文件采用如下命令行
● 第三步构建buildRISC-V交叉编译器
`$ tar xf riscv-gnu-toolchain-clean.tar.gz`
`$ cd riscv-gnu-toolchain`
之后就能够看到和进入当前目录下的riscv-gnu-toolchain文件夹了。
`$ ./configure --prefix=[your.RISCV.install.path]`
● 第三步构建buildRISC-V交叉编译器
`$ make`
`$ cd riscv-gnu-toolchain`
以上命令中,[your.RISCV.install.path]指向的是你的RISC-V交叉编译器安装目录。如果安装是你home目录下的一个子目录如~/riscv-install-dir则最后的make install无需sudoer权限。但如果安装目录是系统目录如/opt/riscv-install-dir则需要sudoer权限即在make install命令前加上sudo
`$ ./configure --prefix=[your.RISCV.install.path]`
● 第四步,设置环境变量
`$ make`
`$ export RISCV=[your.RISCV.install.path]`
以上命令中,[your.RISCV.install.path]指向的是你的RISC-V交叉编译器安装目录。如果安装是你home目录下的一个子目录如~/riscv-install-dir则最后的make install无需sudoer权限。但如果安装目录是系统目录如/opt/riscv-install-dir则需要sudoer权限即在make install命令前加上sudo
`$ export PATH=$PATH:$RISCV/bin`
● 第四步,设置环境变量
以上命令设置了RISCV环境变量指向在第三步中的安装目录并且将交叉编译器的可执行文件所在的目录加入到了系统路径中。这样我们就可以在PKE的工作目录调用RISC-V交叉编译器所包含的工具软件了。
`$ export RISCV=[your.RISCV.install.path]`
### 2.1.2 spike模拟器
`$ export PATH=$PATH:$RISCV/bin`
接下来安装spkie模拟器。首先取得spike的源代码有两个途径一个是从github代码仓库中获取
以上命令设置了RISCV环境变量指向在第三步中的安装目录并且将交叉编译器的可执行文件所在的目录加入到了系统路径中。这样我们就可以在PKE的工作目录调用RISC-V交叉编译器所包含的工具软件了。
`$ git clone https://github.com/riscv/riscv-isa-sim.git`
### 2.1.2 spike模拟器
也可以从百度云盘中下载spike-riscv-isa-sim.tar.gz文件约4.2MB然后用tar命令解压缩。百度云盘的地址以及tar命令解压缩可以参考2.1.1节RISC-V交叉编译器的安装过程。获得spike源代码或解压后将在本地目录看到一个riscv-isa-sim目录。
接下来安装spkie模拟器。首先取得spike的源代码有两个途径一个是从github代码仓库中获取
接下来构建buildspike并安装
`$ git clone https://github.com/riscv/riscv-isa-sim.git`
`$ cd riscv-isa-sim`
也可以从百度云盘中下载spike-riscv-isa-sim.tar.gz文件约4.2MB然后用tar命令解压缩。百度云盘的地址以及tar命令解压缩可以参考2.1.1节RISC-V交叉编译器的安装过程。获得spike源代码或解压后将在本地目录看到一个riscv-isa-sim目录。
`$ ./configure --prefix=$RISCV`
接下来构建buildspike并安装
`$ make`
`$ cd riscv-isa-sim`
`$ make install`
`$ ./configure --prefix=$RISCV`
在以上命令中我们假设RISCV环境变量已经指向了RISC-V交叉编译器的安装目录。如果未建立关联可以将$RISCV替换为2.1.1节中的[your.RISCV.install.path]。
`$ make`
### 2.1.3 PKE
`$ make install`
到github下载课程仓库
在以上命令中我们假设RISCV环境变量已经指向了RISC-V交叉编译器的安装目录。如果未建立关联可以将$RISCV替换为2.1.1节中的[your.RISCV.install.path]。
`$ git clone https://github.com/MrShawCode/pke.git`
### 2.1.3 PKE
克隆完成后将在当前目录看到pke目录。这时可以到pke目录下查看pke的代码结构例如
到github下载课程仓库
`$ cd pke`
`$ git clone https://github.com/MrShawCode/pke.git`
`$ ls`
克隆完成后将在当前目录看到pke目录。这时可以到pke目录下查看pke的代码结构例如
你可以看到当前目录下有如下(部分)内容
`$ cd pke`
.
`$ ls`
├── app
你可以看到当前目录下有如下(部分)内容
├── gradelib.py
.
├── machine
├── app
├── Makefile
├── gradelib.py
├── pk
├── machine
├── pke-lab1
├── Makefile
├── pke.lds
├── pk
└── util
├── pke-lab1
● 首先是app目录里面存放的是实验的测试用例也就是运行在User模式的应用程序例如之前helloworld.c。
├── pke.lds
● gradelib.py、与pke-lab1是测试用的python脚本。
└── util
● machine目录里面存放的是机器模式相关的代码由于本课程的重点在于操作系统在这里你可以无需详细研究。
● 首先是app目录里面存放的是实验的测试用例也就是运行在User模式的应用程序例如之前helloworld.c。
● Makefile文件它定义的整个工程的编译规则。
● gradelib.py、与pke-lab1是测试用的python脚本。
● pke.lds是工程的链接文件。
● machine目录里面存放的是机器模式相关的代码由于本课程的重点在于操作系统在这里你可以无需详细研究。
● util目录下是各模块会用到的工具函数。
● Makefile文件它定义的整个工程的编译规则。
● pk目录里面存放的是pke的主要代码。
● pke.lds是工程的链接文件。
即使未开始做PKE的实验我们的pke代码也是可构建的可以采用以下命令在pke目录下生成pke代理内核
● util目录下是各模块会用到的工具函数。
`$ make`
● pk目录里面存放的是pke的主要代码。
以上命令完成后会在当前目录下会生产obj子目录里面就包含了我们的pke代理内核。pke代理内核的构建过程将在2.2节中详细讨论。
即使未开始做PKE的实验我们的pke代码也是可构建的可以采用以下命令在pke目录下生成pke代理内核
### 2.1.4 环境测试
`$ make`
全部安装完毕后你可以对环境进行测试在pke目录下输入
以上命令完成后会在当前目录下会生产obj子目录里面就包含了我们的pke代理内核。pke代理内核的构建过程将在2.2节中详细讨论。
`$ spike ./obj/pke ./app/elf/app1_2`
### 2.1.4 环境测试
将得到如下输出:
全部安装完毕后你可以对环境进行测试在pke目录下输入
```
PKE IS RUNNING `$ spike ./obj/pke ./app/elf/app1_2`
user mode test illegal instruction!
you need add your code! 将得到如下输出:
```
```
以上命令的作用是首先采用spike模拟一个RISC-V机器该机器支持RV64G指令集并在该机器上运行./app/elf/app1_2应用它的源代码在./app/app1_2.c中。我们知道应用是无法在“裸机”上运行的所以测试命令使用./obj/pke作为应用的代理内核。代理内核的作用是对spike模拟出来的RISC-V机器做简单的“包装”使其能够在spike模拟出来的机器上顺利运行。 PKE IS RUNNING
user mode test illegal instruction!
这里,代理内核的作用是只为特定的应用服务(如本例中的./app/elf/app1_2应用所以可以做到“看菜吃饭”的效果。因为我们这里的应用非常简单所以pke就可以做得极其精简它没有文件系统、没有物理内存管理、没有进程调度、没有操作终端shell等等传统的完整操作系统“必须”具有的组件。在后续的实验中我们将不断提升应用的复杂度并不断完善代理内核。通过这个过程读者将深刻体会操作系统内核对应用支持的机制以及具体的实现细节。 you need add your code!
```
<a name="openeuler"></a>
## 2.3 openEuler操作系统 以上命令的作用是首先采用spike模拟一个RISC-V机器该机器支持RV64G指令集并在该机器上运行./app/elf/app1_2应用它的源代码在./app/app1_2.c中。我们知道应用是无法在“裸机”上运行的所以测试命令使用./obj/pke作为应用的代理内核。代理内核的作用是对spike模拟出来的RISC-V机器做简单的“包装”使其能够在spike模拟出来的机器上顺利运行。
PKE实验将提供基于华为openEuler操作系统的开发方法*具体的华为云使用方法待续*但在openEuler操作系统环境中的交叉编译器安装方法以及其他环节都可参考[2.2 Ubuntu环境](#ubuntu)的命令进行。 这里,代理内核的作用是只为特定的应用服务(如本例中的./app/elf/app1_2应用所以可以做到“看菜吃饭”的效果。因为我们这里的应用非常简单所以pke就可以做得极其精简它没有文件系统、没有物理内存管理、没有进程调度、没有操作终端shell等等传统的完整操作系统“必须”具有的组件。在后续的实验中我们将不断提升应用的复杂度并不断完善代理内核。通过这个过程读者将深刻体会操作系统内核对应用支持的机制以及具体的实现细节。
<a name="openeuler"></a>
## 2.3 openEuler操作系统
PKE实验将提供基于华为openEuler操作系统的开发方法*具体的华为云使用方法待续*但在openEuler操作系统环境中的交叉编译器安装方法以及其他环节都可参考[2.2 Ubuntu环境](#ubuntu)的命令进行。
<a name="preparecode"></a>
## 2.4 riscv-pke实验代码的获取
获取riscv-pke代码前需要首先确认你已经按照[第二章](chapter2_installation.md)的要求完成了开发环境的构建这里我们假设环境是基于Ubuntu或者openEular头歌环境下更多的是界面操作所以无需通过命令行获取代码
环境构建好后通过以下命令下载实验1的代码
(克隆代码仓库)
`$ git clone https://gitee.com/hustos/riscv-pke.git`
克隆完成后将在当前目录应该能看到riscv-pke目录。这时可以到riscv-pke目录下查看文件结构例如
`$ cd riscv-pke`
切换到lab1_1_syscall分支
`$ git checkout lab1_1_syscall`
`$ tree -L 3`
(将看到如下输出)
```
.
├── LICENSE.txt
├── Makefile
├── README.md
├── kernel
│   ├── config.h
│   ├── elf.c
│   ├── elf.h
│   ├── kernel.c
│   ├── kernel.lds
│   ├── machine
│   │   ├── mentry.S
│   │   └── minit.c
│   ├── process.c
│   ├── process.h
│   ├── riscv.h
│   ├── strap.c
│   ├── strap.h
│   ├── strap_vector.S
│   ├── syscall.c
│   └── syscall.h
├── spike_interface
│   ├── atomic.h
│   ├── dts_parse.c
│   ├── dts_parse.h
│   ├── spike_file.c
│   ├── spike_file.h
│   ├── spike_htif.c
│   ├── spike_htif.h
│   ├── spike_memory.c
│   ├── spike_memory.h
│   ├── spike_utils.c
│   └── spike_utils.h
├── user
│   ├── app_helloworld.c
│   ├── user.lds
│   ├── user_lib.c
│   └── user_lib.h
└── util
├── functions.h
├── load_store.S
├── snprintf.c
├── snprintf.h
├── string.c
├── string.h
└── types.h
```
在代码的根目录有以下文件:
- Makefile文件它是make命令即将使用的“自动化编译”脚本
- LICENSE.txt文件即riscv-pke的版权文件里面包含了所有参与开发的人员信息。riscv-pke是开源软件你可以以任意方式自由地使用前提是使用时包含LICENSE.txt文件即可
- README.md文件一个简要的英文版代码说明。
另外是一些子目录,其中:
- kernel目录包含了riscv-pke的内核部分代码
- spike_interface目录是riscv-pke内核与spike模拟器的接口代码如设备树DTB、主机设备接口HTIF等用于接口的初始化和调用
- user目录包含了实验给定应用如lab1_1中的app_helloworld.c以及用户态的程序库文件如lab1_1中的user_lib.c
- util目录包含了一些内核和用户程序公用的代码如字符串处理string.c类型定义types.h等。
在代码的根目录输入以下命令:
`$ make`
进行构造build在环境已配好特别是交叉编译器已加入系统路径的情况下输出如下
```
compiling util/snprintf.c
compiling util/string.c
linking obj/util.a ...
Util lib has been build into "obj/util.a"
compiling spike_interface/dts_parse.c
compiling spike_interface/spike_htif.c
compiling spike_interface/spike_utils.c
compiling spike_interface/spike_file.c
compiling spike_interface/spike_memory.c
linking obj/spike_interface.a ...
Spike lib has been build into "obj/spike_interface.a"
compiling kernel/syscall.c
compiling kernel/elf.c
compiling kernel/process.c
compiling kernel/strap.c
compiling kernel/kernel.c
compiling kernel/machine/minit.c
compiling kernel/strap_vector.S
compiling kernel/machine/mentry.S
linking obj/riscv-pke ...
PKE core has been built into "obj/riscv-pke"
compiling user/app_helloworld.c
compiling user/user_lib.c
linking obj/app_helloworld ...
User app has been built into "obj/app_helloworld"
```
构造完成后在代码根目录会出现一个obj子目录该子目录包含了构造过程中所生成的所有对象文件.o、编译依赖文件.d、静态库.a文件和最终目标ELF文件如./obj/riscv-pke和./obj/app_helloworld
这时我们可以尝试借助riscv-pke内核运行app_helloworld的“Hello world!”程序:
```
$ spike ./obj/riscv-pke ./obj/app_helloworld
In m_start, hartid:0
HTIF is available!
(Emulated) memory size: 2048 MB
Enter supervisor mode...
Application: ./obj/app_helloworld
Application program entry point (virtual address): 0x0000000081000000
Switching to user mode...
call do_syscall to accomplish the syscall and lab1_1 here.
System is shutting down with exit code -1.
```
自此riscv-pke的代码获取和验证已完成。

@ -3,13 +3,12 @@
### 目录 ### 目录
- [3.1 实验1的基础知识](#fundamental) - [3.1 实验1的基础知识](#fundamental)
- [3.1.1 获取riscv-pke代码](#subsec_preparecode) - [3.1.1 RISC-V程序的编译和链接](#subsec_compileandlink)
- [3.1.2 RISC-V程序的编译和链接](#subsec_compileandlink) - [3.1.2 指定符号的逻辑地址](#subsec_lds)
- [3.1.3 指定符号的逻辑地址](#subsec_lds) - [3.1.3 代理内核的构造过程](#subsec_building)
- [3.1.4 代理内核的构造过程](#subsec_building) - [3.1.4 代理内核的启动过程](#subsec_booting)
- [3.1.5 代理内核的启动过程](#subsec_booting) - [3.1.5 ELF文件app的加载过程](#subsec_elf)
- [3.1.6 ELF文件app的加载过程](#subsec_elf) - [3.1.6 spike的HTIF接口](#subsec_htif)
- [3.1.7 spike的HTIF接口](#subsec_htif)
- [3.2 lab1_1 系统调用](#syscall) - [3.2 lab1_1 系统调用](#syscall)
- [给定应用](#lab1_1_app) - [给定应用](#lab1_1_app)
- [实验内容](#lab1_1_content) - [实验内容](#lab1_1_content)
@ -29,148 +28,9 @@
本章我们将首先[获得代码](#subsec_preparecode),接下来介绍[程序的编译链接和ELF文件](#subsec_elfload)的基础知识接着讲述riscv-pke操作系统内核的[启动原理](#subsec_booting)最后开始实验1的3个实验。 本章我们将首先[获得代码](#subsec_preparecode),接下来介绍[程序的编译链接和ELF文件](#subsec_elfload)的基础知识接着讲述riscv-pke操作系统内核的[启动原理](#subsec_booting)最后开始实验1的3个实验。
<a name="subsec_preparecode"></a>
### 3.1.1 获取riscv-pke代码
获取riscv-pke代码前需要首先确认你已经按照[第二章](chapter2_installation.md)的要求完成了开发环境的构建这里我们假设环境是基于Ubuntu或者openEular头歌环境下更多的是界面操作所以无需通过命令行获取代码
环境构建好后通过以下命令下载实验1的代码
(克隆代码仓库)
`$ git clone https://gitee.com/hustos/riscv-pke.git`
克隆完成后将在当前目录应该能看到riscv-pke目录。这时可以到riscv-pke目录下查看文件结构例如
`$ cd riscv-pke`
切换到lab1_1_syscall分支
`$ git checkout lab1_1_syscall`
`$ tree -L 3`
(将看到如下输出)
```
.
├── LICENSE.txt
├── Makefile
├── README.md
├── kernel
│   ├── config.h
│   ├── elf.c
│   ├── elf.h
│   ├── kernel.c
│   ├── kernel.lds
│   ├── machine
│   │   ├── mentry.S
│   │   └── minit.c
│   ├── process.c
│   ├── process.h
│   ├── riscv.h
│   ├── strap.c
│   ├── strap.h
│   ├── strap_vector.S
│   ├── syscall.c
│   └── syscall.h
├── spike_interface
│   ├── atomic.h
│   ├── dts_parse.c
│   ├── dts_parse.h
│   ├── spike_file.c
│   ├── spike_file.h
│   ├── spike_htif.c
│   ├── spike_htif.h
│   ├── spike_memory.c
│   ├── spike_memory.h
│   ├── spike_utils.c
│   └── spike_utils.h
├── user
│   ├── app_helloworld.c
│   ├── user.lds
│   ├── user_lib.c
│   └── user_lib.h
└── util
├── functions.h
├── load_store.S
├── snprintf.c
├── snprintf.h
├── string.c
├── string.h
└── types.h
```
在代码的根目录有以下文件:
- Makefile文件它是make命令即将使用的“自动化编译”脚本
- LICENSE.txt文件即riscv-pke的版权文件里面包含了所有参与开发的人员信息。riscv-pke是开源软件你可以以任意方式自由地使用前提是使用时包含LICENSE.txt文件即可
- README.md文件一个简要的英文版代码说明。
另外是一些子目录,其中:
- kernel目录包含了riscv-pke的内核部分代码
- spike_interface目录是riscv-pke内核与spike模拟器的接口代码如设备树DTB、主机设备接口HTIF等用于接口的初始化和调用
- user目录包含了实验给定应用如lab1_1中的app_helloworld.c以及用户态的程序库文件如lab1_1中的user_lib.c
- util目录包含了一些内核和用户程序公用的代码如字符串处理string.c类型定义types.h等。
在代码的根目录输入以下命令:
`$ make`
进行构造build在环境已配好特别是交叉编译器已加入系统路径的情况下输出如下
```
compiling util/snprintf.c
compiling util/string.c
linking obj/util.a ...
Util lib has been build into "obj/util.a"
compiling spike_interface/dts_parse.c
compiling spike_interface/spike_htif.c
compiling spike_interface/spike_utils.c
compiling spike_interface/spike_file.c
compiling spike_interface/spike_memory.c
linking obj/spike_interface.a ...
Spike lib has been build into "obj/spike_interface.a"
compiling kernel/syscall.c
compiling kernel/elf.c
compiling kernel/process.c
compiling kernel/strap.c
compiling kernel/kernel.c
compiling kernel/machine/minit.c
compiling kernel/strap_vector.S
compiling kernel/machine/mentry.S
linking obj/riscv-pke ...
PKE core has been built into "obj/riscv-pke"
compiling user/app_helloworld.c
compiling user/user_lib.c
linking obj/app_helloworld ...
User app has been built into "obj/app_helloworld"
```
构造完成后在代码根目录会出现一个obj子目录该子目录包含了构造过程中所生成的所有对象文件.o、编译依赖文件.d、静态库.a文件和最终目标ELF文件如./obj/riscv-pke和./obj/app_helloworld
这时我们可以尝试借助riscv-pke内核运行app_helloworld的“Hello world!”程序:
```
$ spike ./obj/riscv-pke ./obj/app_helloworld
In m_start, hartid:0
HTIF is available!
(Emulated) memory size: 2048 MB
Enter supervisor mode...
Application: ./obj/app_helloworld
Application program entry point (virtual address): 0x0000000081000000
Switching to user mode...
call do_syscall to accomplish the syscall and lab1_1 here.
System is shutting down with exit code -1.
```
自此riscv-pke的代码获取和验证已完成。
<a name="subsec_compileandlink"></a> <a name="subsec_compileandlink"></a>
### 3.1.2 RISC-V程序的编译和链接 ### 3.1.1 RISC-V程序的编译和链接
下面我们将简要介绍RISC-V程序的编译和链接相关知识。这里我们仍然假设你已经按照[第二章](chapter2_installation.md)的要求完成了基于Ubuntu或者openEular的开发环境构建如果是在头歌平台可以通过他们提供的交互??进入终端使用里面的交叉编译器已经安装且已加入系统路径。在PKE实验的开发环境中我们通过模拟器spike所构建的目标机是risc-v机器而主机一般采用的是采用x86指令集的Intel处理器openEular可能采用的是基于ARM指令集的华为鲲鹏处理器在这种配置下我们的程序包括PKE操作系统内核以及应用都通过交叉编译器所提供的工具进行编译和链接。虽然risc-v交叉编译器和主机环境下的GCC是同一套体系但它的使用和输出还是有些细微的不同所以有必要对它进行一定的了解。 下面我们将简要介绍RISC-V程序的编译和链接相关知识。这里我们仍然假设你已经按照[第二章](chapter2_installation.md)的要求完成了基于Ubuntu或者openEular的开发环境构建如果是在头歌平台可以通过他们提供的交互??进入终端使用里面的交叉编译器已经安装且已加入系统路径。在PKE实验的开发环境中我们通过模拟器spike所构建的目标机是risc-v机器而主机一般采用的是采用x86指令集的Intel处理器openEular可能采用的是基于ARM指令集的华为鲲鹏处理器在这种配置下我们的程序包括PKE操作系统内核以及应用都通过交叉编译器所提供的工具进行编译和链接。虽然risc-v交叉编译器和主机环境下的GCC是同一套体系但它的使用和输出还是有些细微的不同所以有必要对它进行一定的了解。
@ -371,7 +231,7 @@ Disassembly of section .text:
<a name="subsec_lds"></a> <a name="subsec_lds"></a>
### 3.1.3 指定符号的逻辑地址 ### 3.1.2 指定符号的逻辑地址
编译器在链接过程中一个重要的任务就是为源程序中的符号symbol赋予逻辑地址。例如在以上`sections`的例子中,我们通过`objdump`命令得知helloworld.c源文件的main函数所对应的逻辑地址为0x000000000001014e而且对于任意ELF中的段segment或节section而言它的逻辑地址必然是从某个地址开始的一段连续地址空间。 编译器在链接过程中一个重要的任务就是为源程序中的符号symbol赋予逻辑地址。例如在以上`sections`的例子中,我们通过`objdump`命令得知helloworld.c源文件的main函数所对应的逻辑地址为0x000000000001014e而且对于任意ELF中的段segment或节section而言它的逻辑地址必然是从某个地址开始的一段连续地址空间。
@ -471,7 +331,7 @@ Disassembly of section .text:
<a name="subsec_building"></a> <a name="subsec_building"></a>
### 3.1.4 代理内核的构造过程 ### 3.1.3 代理内核的构造过程
这里我们讨论lab1_1中代理内核以及其上运行的应用的构造build过程。PKE实验采用了Linux中广泛采用的make软件包完成内核、支撑库以及应用的构造。关于Makefile的编写我们建议读者阅读[这篇文章](https://blog.csdn.net/foryourface/article/details/34058577)了解make文件的基础知识这里仅讨论lab1_1的Makefile以及对应的构造过程。PKE的后续实验实际上采用的Makefile跟lab1_1的非常类似所以我们在后续章节中不再对它们的构建过程进行讨论。 这里我们讨论lab1_1中代理内核以及其上运行的应用的构造build过程。PKE实验采用了Linux中广泛采用的make软件包完成内核、支撑库以及应用的构造。关于Makefile的编写我们建议读者阅读[这篇文章](https://blog.csdn.net/foryourface/article/details/34058577)了解make文件的基础知识这里仅讨论lab1_1的Makefile以及对应的构造过程。PKE的后续实验实际上采用的Makefile跟lab1_1的非常类似所以我们在后续章节中不再对它们的构建过程进行讨论。
@ -604,7 +464,7 @@ Disassembly of section .text:
<a name="subsec_booting"></a> <a name="subsec_booting"></a>
### 3.1.5 代理内核的启动过程 ### 3.1.4 代理内核的启动过程
在3.1.1中我们获取riscv-pke的代码并完成构造步骤后我们将通过以下命令开始lab1_1所给定的应用的执行 在3.1.1中我们获取riscv-pke的代码并完成构造步骤后我们将通过以下命令开始lab1_1所给定的应用的执行
@ -871,7 +731,7 @@ s_start函数在kernel/kernel.c文件中定义
<a name="subsec_elf"></a> <a name="subsec_elf"></a>
### 3.1.6 ELF文件app的加载过程 ### 3.1.5 ELF文件app的加载过程
这里我们对load_user_program()函数进行讨论它在kernel/kernel.c中定义 这里我们对load_user_program()函数进行讨论它在kernel/kernel.c中定义
@ -982,7 +842,7 @@ s_start函数在kernel/kernel.c文件中定义
<a name="subsec_htif"></a> <a name="subsec_htif"></a>
### 3.1.7 spike的HTIF接口 ### 3.1.6 spike的HTIF接口
spike提供的HTIFHost-Target InterFace接口的原理可以用下图说明 spike提供的HTIFHost-Target InterFace接口的原理可以用下图说明

Loading…
Cancel
Save