377 lines
14 KiB
Diff
377 lines
14 KiB
Diff
|
|
From 08eae86c65a91827a0f0c8de3849b6f46f097fba Mon Sep 17 00:00:00 2001
|
|||
|
|
From: Jiajie Li <lijiajie11@huawei.com>
|
|||
|
|
Date: Mon, 21 Feb 2022 18:10:01 +0800
|
|||
|
|
Subject: [PATCH 08/10] docs/boot: update detailed usage for standard boot
|
|||
|
|
|
|||
|
|
1. Fix some clerical error in boot cmdline.
|
|||
|
|
2. Add download link for kernel image.
|
|||
|
|
3. Differentiate the two modes supported by standard boot to
|
|||
|
|
make it easier to understand.
|
|||
|
|
|
|||
|
|
Signed-off-by: Jiajie Li <lijiajie11@huawei.com>
|
|||
|
|
---
|
|||
|
|
docs/boot.ch.md | 94 +++++++++++++++++++++++++++----------------------
|
|||
|
|
docs/boot.md | 89 +++++++++++++++++++++++++---------------------
|
|||
|
|
2 files changed, 99 insertions(+), 84 deletions(-)
|
|||
|
|
|
|||
|
|
diff --git a/docs/boot.ch.md b/docs/boot.ch.md
|
|||
|
|
index b8eec27..31153a9 100644
|
|||
|
|
--- a/docs/boot.ch.md
|
|||
|
|
+++ b/docs/boot.ch.md
|
|||
|
|
@@ -1,13 +1,13 @@
|
|||
|
|
# StratoVirt 启动准备
|
|||
|
|
|
|||
|
|
-StratoVirt提供了微虚拟机和标准虚拟机两种机型。两种机型的启动过程如下。
|
|||
|
|
+StratoVirt提供了轻量虚拟机和标准虚拟机两种机型。两种机型的启动过程如下。
|
|||
|
|
|
|||
|
|
-## 微虚拟机启动过程
|
|||
|
|
+## 轻量虚拟机启动过程
|
|||
|
|
|
|||
|
|
### 1. 构建内核镜像
|
|||
|
|
|
|||
|
|
-StratoVirt的微虚拟机机型在x86_64和aarch64平台都支持PE格式或是bzImage格式
|
|||
|
|
-(仅x86_64平台支持)的内核镜像。通过以下步骤来构建内核镜像:
|
|||
|
|
+StratoVirt的轻量虚拟机机型在x86_64平台上支持PE格式或是bzImage格式的内核镜像,在
|
|||
|
|
+aarch64平台上支持PE格式的内核镜像。通过以下步骤来构建内核镜像:
|
|||
|
|
|
|||
|
|
1. 首先,获取openEuler内核源码:
|
|||
|
|
|
|||
|
|
@@ -22,7 +22,7 @@ StratoVirt的微虚拟机机型在x86_64和aarch64平台都支持PE格式或是b
|
|||
|
|
$ cd /usr/src/linux-5.10.0-0.0.0.7.oe1.$(uname -m)/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
-2. 配置linux内核信息。你可以使用 [我们提供的微虚拟机内核配置文件](./kernel_config/micro_vm)
|
|||
|
|
+2. 配置linux内核信息。你可以使用 [我们提供的轻量虚拟机内核配置文件](./kernel_config/micro_vm)
|
|||
|
|
并且将配置文件重命名为`.config`拷贝至`kernel`路径下。 当然你也可以通过命令修改内
|
|||
|
|
核编译选项:
|
|||
|
|
|
|||
|
|
@@ -33,12 +33,12 @@ StratoVirt的微虚拟机机型在x86_64和aarch64平台都支持PE格式或是b
|
|||
|
|
3. 构建并将内核镜像转换为PE格式。
|
|||
|
|
|
|||
|
|
```shell
|
|||
|
|
- $ make -j vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
+ $ make -j$(nproc) vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
4. 如果你想要在x86_64平台编译bzImage格式内核镜像。
|
|||
|
|
```shell
|
|||
|
|
- $ make -j bzImage
|
|||
|
|
+ $ make -j$(nproc) bzImage
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 构建rootfs镜像
|
|||
|
|
@@ -66,33 +66,10 @@ Rootfs镜像是一种文件系统镜像。在StratoVirt启动时可以挂载带
|
|||
|
|
标准虚拟机有两种启动方式,第一种使用kernel+rootfs;另一种是使用预先安装好guest 操
|
|||
|
|
作系统的raw格式镜像。
|
|||
|
|
|
|||
|
|
-### 1. 构建内核镜像
|
|||
|
|
-
|
|||
|
|
-StratoVirt的标准虚拟机机型支持x86_64平台的bzImage格式内核镜像和aarch64平台的PE格
|
|||
|
|
-式内核镜像。内核镜像构建如下:
|
|||
|
|
-
|
|||
|
|
-1. 首先,获取openEuler内核源码:
|
|||
|
|
-
|
|||
|
|
- ```shell
|
|||
|
|
- $ git clone -b kernel-5.10 --depth=1 https://gitee.com/openeuler/kernel
|
|||
|
|
- $ cd kernel
|
|||
|
|
- ```
|
|||
|
|
-
|
|||
|
|
-2. 配置linux内核信息。你可以使用 [我们提供的标准虚拟机内核配置文件](./kernel_config/standard_vm)
|
|||
|
|
- 并且将配置文件重命名为`.config`拷贝至`kernel`路径下。
|
|||
|
|
-
|
|||
|
|
-3. 构建内核镜像
|
|||
|
|
-
|
|||
|
|
- ```shell
|
|||
|
|
- # 在aarch64平台,将内核镜像转换为PE格式。
|
|||
|
|
- $ make -j vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
-
|
|||
|
|
- # 在x86_64平台,将内核镜像转换为bzImage格式.
|
|||
|
|
- $ make -j bzImage
|
|||
|
|
- ```
|
|||
|
|
-
|
|||
|
|
+接下来讲解如何通过以上所述的两种方式启动标准虚拟机。以上两种启动方式均需使用标准启动
|
|||
|
|
+固件,为此首先讲解如何获取标准启动固件。
|
|||
|
|
|
|||
|
|
-### 2. 获取标准启动固件
|
|||
|
|
+### 1. 获取标准启动固件
|
|||
|
|
|
|||
|
|
标准启动需要启动固件。Stratovirt仅支持在x86_64和aarch64平台上从UEFI(统一可扩展
|
|||
|
|
固件接口)启动。
|
|||
|
|
@@ -103,7 +80,7 @@ EDK2是一个实现了UEFI规范的开源项目。我们使用EDK2作为固件
|
|||
|
|
有两种方法可以获取EDK2二进制文件,通过yum源直接安装或从源代码编译。具体步骤如下。
|
|||
|
|
请注意,EDK2二进制文件包含两个文件,一个用于存储可执行代码,另一个用于存储引导数据。
|
|||
|
|
|
|||
|
|
-#### 2.1 直接安装EDK2
|
|||
|
|
+#### 1.1 直接安装EDK2
|
|||
|
|
|
|||
|
|
在x86_64平台, 运行
|
|||
|
|
|
|||
|
|
@@ -121,7 +98,7 @@ $ sudo yum install -y edk2-aarch64
|
|||
|
|
`/usr/share/edk2/ovmf` 目录下。 在aarch64平台, `QEMU_EFI-pflash.raw` 和
|
|||
|
|
`vars-template-pflash.raw` 文件会存在于`/usr/share/edk2/aarch64` 目录下。
|
|||
|
|
|
|||
|
|
-#### 2.2 从源代码编译
|
|||
|
|
+#### 1.2 从源代码编译
|
|||
|
|
|
|||
|
|
```shell
|
|||
|
|
# 安装必要依赖包用于编译edk2。
|
|||
|
|
@@ -169,13 +146,44 @@ fi
|
|||
|
|
目录下。在aarch64平台, `STRATOVIRT_EFI.raw` 和 `STRATOVIRT_VAR.raw` 文件会位于
|
|||
|
|
`/home` 目录下.
|
|||
|
|
|
|||
|
|
-### 3. 构建rootfs镜像
|
|||
|
|
+### 2. 以 kernel + rootfs 方式启动标准虚拟机
|
|||
|
|
+
|
|||
|
|
+#### 2.1 构建内核镜像
|
|||
|
|
+
|
|||
|
|
+StratoVirt的标准虚拟机机型支持x86_64平台的bzImage格式内核镜像和aarch64平台的PE格
|
|||
|
|
+式内核镜像。内核镜像构建如下:
|
|||
|
|
+
|
|||
|
|
+1. 获取openEuler内核源码:
|
|||
|
|
+
|
|||
|
|
+ ```shell
|
|||
|
|
+ $ git clone -b kernel-5.10 --depth=1 https://gitee.com/openeuler/kernel
|
|||
|
|
+ $ cd kernel
|
|||
|
|
+ ```
|
|||
|
|
+
|
|||
|
|
+2. 配置linux内核信息。你可以使用我们提供的标准虚拟机 [内核配置文件](./kernel_config/standard_vm)
|
|||
|
|
+ 并且将配置文件重命名为`.config`拷贝至`kernel`路径下。
|
|||
|
|
+
|
|||
|
|
+3. 构建内核镜像
|
|||
|
|
+
|
|||
|
|
+ ```shell
|
|||
|
|
+ # 在aarch64平台,将内核镜像转换为PE格式。
|
|||
|
|
+ $ make -j$(nproc) vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
+
|
|||
|
|
+ # 在x86_64平台,将内核镜像转换为bzImage格式.
|
|||
|
|
+ $ make -j$(nproc) bzImage
|
|||
|
|
+ ```
|
|||
|
|
+
|
|||
|
|
+除了手动构建内核镜像的方式以外,也可以直接从 openEuler 官网下载对应的
|
|||
|
|
+[内核镜像](https://repo.openeuler.org/openEuler-21.09/stratovirt_img/x86_64/std-vmlinuxz)。
|
|||
|
|
+
|
|||
|
|
+#### 2.2 构建rootfs镜像
|
|||
|
|
|
|||
|
|
-为标准虚拟机构建rootfs镜像实际上与微虚拟机相同。你可以通过[附录](#2附录)查看更多
|
|||
|
|
+为标准虚拟机构建rootfs镜像实际上与轻量虚拟机相同。你可以通过[附录](#2附录)查看更多
|
|||
|
|
的详细信息。
|
|||
|
|
|
|||
|
|
+### 3. 以 raw 格式镜像启动标准虚拟机
|
|||
|
|
|
|||
|
|
-### 4. 获取 raw 格式镜像
|
|||
|
|
+#### 3.1 获取 raw 格式镜像
|
|||
|
|
|
|||
|
|
你可以从 openEuler 官网下载已经安装好的 [qcow2 镜像](https://repo.openeuler.org/openEuler-21.03/virtual_machine_img/x86_64/openEuler-21.03-x86_64.qcow2.xz)。
|
|||
|
|
|
|||
|
|
@@ -189,7 +197,7 @@ $ qemu-img convert -f qcow2 -O raw openEuler-21.03-x86_64.qcow2 openEuler-21.03-
|
|||
|
|
|
|||
|
|
至此就获得了可以使用的 raw 格式镜像。
|
|||
|
|
|
|||
|
|
-### 5. 启动命令行样例
|
|||
|
|
+### 4. 启动命令行样例
|
|||
|
|
|
|||
|
|
请注意,标准虚拟机需要两个PFlash设备,它们将使用来自与EDK2二进制的两个固件文件。
|
|||
|
|
如果你不需要保持启动信息,单元序列为1的数据存储文件可以被省略。但是单元序号为0的
|
|||
|
|
@@ -215,11 +223,11 @@ fi
|
|||
|
|
-kernel /path/to/kernel \
|
|||
|
|
-smp 1 \
|
|||
|
|
-m 2G \
|
|||
|
|
- -append "console=${con} reboot=k panic=1 root=/dev/vda" \
|
|||
|
|
+ -append "console=${con} reboot=k panic=1 root=/dev/vda rw" \
|
|||
|
|
-drive file=/path/to/rootfs,id=rootfs,readonly=off,direct=off \
|
|||
|
|
-device virtio-blk-device,drive=rootfs,id=rootfs \
|
|||
|
|
-drive file=/path/to/OVMF_CODE.fd,if=pflash,unit=0,readonly=true \
|
|||
|
|
- -drive file=/path/to/OVMF_VARS.fd,if=pfalsh,unit=1 \
|
|||
|
|
+ -drive file=/path/to/OVMF_VARS.fd,if=pflash,unit=1 \
|
|||
|
|
-qmp unix:/path/to/socket,server,nowait \
|
|||
|
|
-serial stdio
|
|||
|
|
```
|
|||
|
|
@@ -232,11 +240,11 @@ fi
|
|||
|
|
-kernel /path/to/kernel \
|
|||
|
|
-smp 1 \
|
|||
|
|
-m 2G \
|
|||
|
|
- -append "console=${con} reboot=k panic=1 root=/dev/vda" \
|
|||
|
|
+ -append "console=${con} reboot=k panic=1 root=/dev/vda rw" \
|
|||
|
|
-drive file=/path/to/rootfs,id=rootfs,readonly=off,direct=off \
|
|||
|
|
-device virtio-blk-device,drive=rootfs \
|
|||
|
|
-drive file=/path/to/OVMF_CODE.fd,if=pflash,unit=0,readonly=true \
|
|||
|
|
- -drive file=/path/to/OVMF_VARS.fd,if=pfalsh,unit=1 \
|
|||
|
|
+ -drive file=/path/to/OVMF_VARS.fd,if=pflash,unit=1 \
|
|||
|
|
-qmp unix:/path/to/socket,server,nowait \
|
|||
|
|
-serial stdio
|
|||
|
|
```
|
|||
|
|
diff --git a/docs/boot.md b/docs/boot.md
|
|||
|
|
index f7227df..64d75b4 100644
|
|||
|
|
--- a/docs/boot.md
|
|||
|
|
+++ b/docs/boot.md
|
|||
|
|
@@ -7,9 +7,9 @@ boot process of these two machines are as follows.
|
|||
|
|
|
|||
|
|
### 1. Build kernel
|
|||
|
|
|
|||
|
|
-The microvm machine type of StratoVirt supports PE or bzImage (only x86_64) format
|
|||
|
|
-kernel images on both x86_64 and aarch64 platforms. Kernel image can be built with
|
|||
|
|
-following steps:
|
|||
|
|
+The microvm machine type of StratoVirt supports PE or bzImage format kernel images
|
|||
|
|
+on x86_64 platforms, and supports PE format kernel images on aarch64 platforms.
|
|||
|
|
+Kernel image can be built with following steps:
|
|||
|
|
|
|||
|
|
1. Firstly, get the openEuler kernel source code with:
|
|||
|
|
|
|||
|
|
@@ -35,12 +35,12 @@ and copy it to `kernel` path as `.config`. You can also modify config options by
|
|||
|
|
3. Build and transform kernel image to PE format.
|
|||
|
|
|
|||
|
|
```shell
|
|||
|
|
- $ make -j vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
+ $ make -j$(nproc) vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
4. If you want to compile bzImage format kernel in x86_64.
|
|||
|
|
```shell
|
|||
|
|
- $ make -j bzImage
|
|||
|
|
+ $ make -j$(nproc) bzImage
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Build rootfs
|
|||
|
|
@@ -68,34 +68,10 @@ be mounted at boot time in StratoVirt. You can check [Appendix](#2Appendix).
|
|||
|
|
Standard VMs can boot in two modes. The first mode is kernel + rootfs.The other
|
|||
|
|
is to use the raw image that has been preinstalled with the guest OS.
|
|||
|
|
|
|||
|
|
-### 1. Build kernel
|
|||
|
|
-
|
|||
|
|
-The standard_ machine in StratoVirt supports bzImage format kernel image
|
|||
|
|
-on x86_64 platform; and supports PE format kernel image on aarch64 platform.
|
|||
|
|
-Kernel image can be built with:
|
|||
|
|
-
|
|||
|
|
-1. Firstly, get the openEuler kernel source code with:
|
|||
|
|
-
|
|||
|
|
- ```shell
|
|||
|
|
- $ git clone -b kernel-5.10 --depth=1 https://gitee.com/openeuler/kernel
|
|||
|
|
- $ cd kernel
|
|||
|
|
- ```
|
|||
|
|
-
|
|||
|
|
-2. Configure your linux kernel. You should use [our recommended standard_vm config]
|
|||
|
|
-(./kernel_config/standard_vm) and copy it to `kernel` path as `.config`.
|
|||
|
|
-
|
|||
|
|
-3. Build kernel image
|
|||
|
|
-
|
|||
|
|
- ```shell
|
|||
|
|
- # on aarch64 platform, transform kernel image to PE format.
|
|||
|
|
- $ make -j vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
-
|
|||
|
|
- # on x86_64 platform, get bzImage format kernel image.
|
|||
|
|
- $ make -j bzImage
|
|||
|
|
- ```
|
|||
|
|
-
|
|||
|
|
+The preceding two boot modes both require standard boot firmware. So we first
|
|||
|
|
+describe how to obtain the standard boot firmware.
|
|||
|
|
|
|||
|
|
-### 2. Get firmware for standard boot
|
|||
|
|
+### 1. Get firmware for standard boot
|
|||
|
|
|
|||
|
|
Standard boot needs firmware. Stratovirt only supports booting from UEFI (Unified
|
|||
|
|
Extensible Firmware Interface) on x86_64 and aarch64 platform.
|
|||
|
|
@@ -108,7 +84,7 @@ or compiling from source code. The specific steps are as follows. Notes that EDK
|
|||
|
|
binary contains two files, one for executable code storage and the other for boot
|
|||
|
|
data storage.
|
|||
|
|
|
|||
|
|
-#### 2.1 Directly install EDK II
|
|||
|
|
+#### 1.1 Directly install EDK II
|
|||
|
|
|
|||
|
|
On x86_64 platform, run
|
|||
|
|
|
|||
|
|
@@ -126,7 +102,7 @@ After installing edk2, on x86_64 platform, `OVMF_CODE.fd` and `OVMF_VARS.fd` are
|
|||
|
|
located in `/usr/share/edk2/ovmf` directory. On aarch64 platform, `QEMU_EFI-pflash.raw`
|
|||
|
|
and `vars-template-pflash.raw` are located in `/usr/share/edk2/aarch64` directory.
|
|||
|
|
|
|||
|
|
-#### 2.2 Compile from source code
|
|||
|
|
+#### 1.2 Compile from source code
|
|||
|
|
|
|||
|
|
```shell
|
|||
|
|
# Install necessary packages to compile edk2.
|
|||
|
|
@@ -174,13 +150,44 @@ After compiling edk2, on x86_64 platform, `OVMF_CODE.fd` and `OVMF_VARS.fd` loca
|
|||
|
|
underneath `/home` directory. On aarch64 platform, `STRATOVIRT_EFI.raw` and
|
|||
|
|
`STRATOVIRT_VAR.raw` locates underneath `/home` directory.
|
|||
|
|
|
|||
|
|
-### 3. Build rootfs
|
|||
|
|
+### 2. Boot with kernel and rootfs
|
|||
|
|
+#### 2.1 Build kernel
|
|||
|
|
+
|
|||
|
|
+The standard_ machine in StratoVirt supports bzImage format kernel image
|
|||
|
|
+on x86_64 platform; and supports PE format kernel image on aarch64 platform.
|
|||
|
|
+Kernel image can be built with:
|
|||
|
|
+
|
|||
|
|
+1. Firstly, get the openEuler kernel source code with:
|
|||
|
|
+
|
|||
|
|
+ ```shell
|
|||
|
|
+ $ git clone -b kernel-5.10 --depth=1 https://gitee.com/openeuler/kernel
|
|||
|
|
+ $ cd kernel
|
|||
|
|
+ ```
|
|||
|
|
+
|
|||
|
|
+2. Configure your linux kernel. You should use [our recommended standard_vm config]
|
|||
|
|
+(./kernel_config/standard_vm) and copy it to `kernel` path as `.config`.
|
|||
|
|
+
|
|||
|
|
+3. Build kernel image
|
|||
|
|
+
|
|||
|
|
+ ```shell
|
|||
|
|
+ # on aarch64 platform, transform kernel image to PE format.
|
|||
|
|
+ $ make -j$(nproc) vmlinux && objcopy -O binary vmlinux vmlinux.bin
|
|||
|
|
+
|
|||
|
|
+ # on x86_64 platform, get bzImage format kernel image.
|
|||
|
|
+ $ make -j$(nproc) bzImage
|
|||
|
|
+ ```
|
|||
|
|
+In addition to manually building the kernel image, you can also download the
|
|||
|
|
+[kernel image](https://repo.openeuler.org/openEuler-21.09/stratovirt_img/x86_64/std-vmlinuxz)
|
|||
|
|
+from the openEuler official website.
|
|||
|
|
+
|
|||
|
|
+#### 2.2 Build rootfs
|
|||
|
|
|
|||
|
|
The building of rootfs for standard VM is exactly the same with microvm. You can
|
|||
|
|
check [Appendix](#2Appendix) for more detailed information.
|
|||
|
|
|
|||
|
|
|
|||
|
|
-### 4. Get raw image
|
|||
|
|
+### 3. Boot with raw image
|
|||
|
|
+#### 3.1 Get raw image
|
|||
|
|
|
|||
|
|
You can download the installed [qcow2 image](https://repo.openeuler.org/openEuler-21.03/virtual_machine_img/x86_64/openEuler-21.03-x86_64.qcow2.xz)
|
|||
|
|
from the OpenEuler official website.
|
|||
|
|
@@ -195,7 +202,7 @@ $ qemu-img convert -f qcow2 -O raw openEuler-21.03-x86_64.qcow2 openEuler-21.03-
|
|||
|
|
|
|||
|
|
Now the available raw image is obtained.
|
|||
|
|
|
|||
|
|
-### 5. Boot command line sample
|
|||
|
|
+### 4. Boot command line sample
|
|||
|
|
|
|||
|
|
Note that standard need two PFlash devices which will use two firmware files from
|
|||
|
|
EDK II binary. If you don't need to store boot information, data storage file can
|
|||
|
|
@@ -221,11 +228,11 @@ fi
|
|||
|
|
-kernel /path/to/kernel \
|
|||
|
|
-smp 1 \
|
|||
|
|
-m 2G \
|
|||
|
|
- -append "console=${con} reboot=k panic=1 root=/dev/vda" \
|
|||
|
|
+ -append "console=${con} reboot=k panic=1 root=/dev/vda rw" \
|
|||
|
|
-drive file=/path/to/rootfs,id=rootfs,readonly=off,direct=off \
|
|||
|
|
-device virtio-blk-device,drive=rootfs,id=rootfs \
|
|||
|
|
-drive file=/path/to/OVMF_CODE.fd,if=pflash,unit=0,readonly=true \
|
|||
|
|
- -drive file=/path/to/OVMF_VARS.fd,if=pfalsh,unit=1 \
|
|||
|
|
+ -drive file=/path/to/OVMF_VARS.fd,if=pflash,unit=1 \
|
|||
|
|
-qmp unix:/path/to/socket,server,nowait \
|
|||
|
|
-serial stdio
|
|||
|
|
```
|
|||
|
|
@@ -240,10 +247,10 @@ The command for booting with the raw image is as follows:
|
|||
|
|
-drive file=/path/to/raw_image,id=raw_image,readonly=off,direct=off \
|
|||
|
|
-device virtio-blk-device,drive=raw_image \
|
|||
|
|
-drive file=/path/to/OVMF_CODE.fd,if=pflash,unit=0,readonly=true \
|
|||
|
|
- -drive file=/path/to/OVMF_VARS.fd,if=pfalsh,unit=1 \
|
|||
|
|
+ -drive file=/path/to/OVMF_VARS.fd,if=pflash,unit=1 \
|
|||
|
|
-qmp unix:/path/to/socket,server,nowait \
|
|||
|
|
-serial stdio
|
|||
|
|
-```F
|
|||
|
|
+```
|
|||
|
|
|
|||
|
|
## Appendix
|
|||
|
|
|
|||
|
|
--
|
|||
|
|
2.25.1
|
|||
|
|
|