虚拟化 之一 详解 jailhouse 架构及原理、软硬件要求、源码文件、基本组件
Jailhouse 是一个基于 Linux 实现的针对创建工业级应用程序的小型 Hypervisor,是由西门子公司的 Jan Kiszka 于 2013 年开发的,并得到了官方 Linux 内核的支持,在开源社区中获得了知名度和吸引力。
Jailhouse
Jailhouse 是一种轻量级的虚拟化技术,可以将多个操作系统(或者裸机程序)同时运行在同一台硬件上。它是一个基于 Linux 的静态分区的 Hypervisor,但本身并不改造 Linux 内核,而是利用 Linux 系统的开放性,增加一个或多个实时操作系统,实现多系统在一个多核处理器上运行。
Jailhouse 不会模拟不存在的硬件资源,也不包含任何的调度处理,而是利用虚拟化技术将硬件资源划分为多个被称为 Cell 的独立空间,并将每个 Cell 分配给不同的虚拟机。每个 Cell 独占自己的处理器核心、内存、I/O 设备和中断控制器等资源。这样可以确保不同虚拟机之间的资源互相隔离,提高系统的可靠性。
Root Cell
当 Jailhouse 启动之后,原来的负责启动 Jailhouse 的 Linux 系统所在空间就被称为 Root Cell。对于所有 Jailhouse 虚拟机的管理都是在 Root Cell 中的 Linux 系统中通过 Jailhouse 提供的命令行工具来实现的。
Non-root Cell
除了 Root Cell 之外的每个独立的 Cell 就是一个 Non-root Cell,每个 Non-root Cell 就对应一个虚拟机。Non-root Cell 通过 Root Cell 进行管理,只要资源够用,Non-root Cell 可以有任意多个。
inmate
Non-root Cell 虚拟机中运行的系统(也可能是一个裸机程序)被称为 inmate,目前可以是 Linux、FreeRTOS、ERIKA3 RTOS、Zephyr 其中之一。Jailhouse 都是直接将其作为原始二进制文件(不是 ELF 文件),直接加载到其对应的配置文件中指定的内存中去运行。
在 x86 平台下,由于 Jailhouse 只向 Non-root Cell 的 inmate 暴露最小环境,可用的资源不足以在不进行修改的情况下引导标准的 Linux 系统。为此,西门子官方提供了一个补丁队列,以便在 x86 平台下的 Non-root Cell 中启动 Linux。同时在构建时需要注意以下几点:
- 需要使能
CONFIG_JAILHOUSE_GUEST
- 禁用
CONFIG_SERIO
和CONFIG_PM_TRACE_RTC
- 一般还应该禁用所有不需要的驱动程序和特性,以避免不需要的 probe,并且使镜像大小和内存占用最小化
在 ARM / ARM64 平台上,引导 Linux 内核要比在 x86 平台上简单得多,因此在这种情况下,我们不需要为 Non-root Cell 特别修改 Linux 内核。
内存布局
Jailhouse 的实现需要使用一块连续内存,这块内存需要在启动 Linux 时保留出来。至于内存具体用哪一块,则取决于自己的设备,如下以 0x100000000 为例的示意图如下所示:
Cell 间通信
虽然 Jailhouse 将硬件资源进行了划分到了不同的 Cell 中,通过虚拟机监控器实现了相互隔离,但在实际应用过程中,Cell 间也需进行通信。为此,Jailhouse 通过虚拟 ivshmem(Inter-VM shared memory) PCI 设备在 Cell 之间提供共享内存和信号机制。一个通道将两个分区 1:1 对应地连接起来。
环境要求
Jailhouse 是一个依托于 Linux Kernel 的开放性从而直接使用硬件平台提供的虚拟化技术来实现的虚拟化解决方案。因此,Jailhouse 需要 Linux Kernel 的支持及硬件平台的虚拟化技术。
硬件要求
Jailhouse 利用 Intel 的 VT-x、AMD 的 AMD-V 和 ARM 虚拟化扩展等硬件辅助虚拟化技术来划分物理资源和限制虚拟机对这些资源的访问,从而实现对系统资源的隔离控制。
x86 架构
- 针对 Intel 平台,需要 64 位架构以及 VMX(Virtual Machine Extensions,Intel CPU 中使用
vmx
标识 Intel 的 VT-x 虚拟化技术) 技术,具体细节:-
具备 EPT(Extended Page Tables,扩展页表)支持。扩展页表是用于内存管理单元(MMU)的 Intel 第二代 x86 虚拟化技术。 直接在实模式下启动逻辑 CPU 就需要 EPT 的支持,这一功能在英特尔的行话中称为无限制访客模式,并在 Westmere 微体系结构中引入。
Intel 的 Core i3、Core i5、Core i7 和 Core i9 CPU 等均支持 EPT
-
Preemption Timer 是一种可以周期性使 VM 触发 VMEXIT 的一种机制。即设置了 Preemption Timer 之后,可以使得虚拟机在指定的 TSC cycle 之后产生一次 VMEXIT 并设置对应的 exit_reason,trap 到 VMM 中。
-
支持中断重映射的 Intel IOMMU(Intel 官方称为 VT-d(Virtualization Technology for Directed I/O))
-
- 针对 AMD 平台,需要 64 位架构以及 SVM(AMD Secure Virtual Machine(这个是 AMD 内部的研发代号,后来统一使用 AMD-V 作为对外名称),AMD CPU 中使用
svm
来表示 AMD 的 AMD-V 虚拟化技术)技术:- 必须具备 NPT(Nested Page Tables,嵌套页表)支持。嵌套页表现在称为快速虚拟化索引(Rapid Virtualization Indexing,RVI)是 AMD 第二代处理器内存管理单元(MMU)硬件辅助虚拟化技术。
- 推荐具备 Decode Assists 支持
- AMD IOMMU(AMD 官方称为 AMD-Vi(AMD’s I/O Virtualization Technology))目前不被支持,但后续需要
- 至少两个逻辑 CPU 核心。注意这里是逻辑 CPU 核心,不是物理 CPU 核心。
- 在 x86 平台下,需要在 BIOS 或 UEFI 中开启虚拟化功能!
EPT 和 NPT 是 Intel 和 AMD 两家对于 Second Level Address Translation(SLAT,二级地址转换)在自家 CPU 上的具体实现。SLAT 是一种硬件辅助虚拟化技术,可以避免与软件管理的影子页表相关的开销。此外,IOMMU 也经常被我们称为 PCI 直通。
ARM 架构
-
ARMv8 架构或者是带有虚拟化扩展的 ARMv7 架构。ARM 的虚拟化扩展支持 SLAT,即由 Stage-2 MMU 提供的 Stage-2 页表。客户机使用 Stage-1 MMU。该支持在 ARMv7ve 架构中作为可选添加,并且在 ARMv8(32 位和 64 位)架构中也受支持。
-
至少两个逻辑 CPU 核心
-
支持如下 AArch32 架构的开发板
- Banana Pi (see more)
- Orange Pi Zero (256 MB version)
- NVIDIA Jetson TK1
- ARM Versatile Express with Cortex-A15 or A7 cores (includes ARM Fast Model)
- emtrion emCON-RZ/G1x series based on Renesas RZ/G (see more)
-
支持如下 AArch64 架构的开发板
- AMD Seattle / SoftIron Overdrive 3000
- LeMaker HiKey
- NVIDIA Jetson TX1 and TX2
- Xilinx ZCU102 (ZynqMP evaluation board)
- NXP MCIMX8M-EVK
内核要求
Jailhouse 的构建是依赖于 Linux Kernel 的,因此,必须使用对应的 Linux Kernel。但是,不同版本的 Linux Kernel 对于 Jailhouse 的支持情况不尽相同。在使用比较新的 Linux Kernel 时,需要对 Linux Kernel 进行打补丁,否则将出现各种错误!
x86 架构
-
必须禁用 Linux Kernel 对 VT-d IOMMU 的使用(DMAR)。这个可以通过在 GRUB 配置文件中设置
GRUB_CMDLINE_LINUX = "intel_iommu=off"
(IOMMU 硬件有 intel/amd/arm 的等,一般用 intel 的硬件) 这个启动参数来处理。- kvm 一定要用 intel_iommu=on,DPDK/SPDK 如果绑定 vfio-pci 那也一定要求 intel_iommu=on,如果绑定 uio/igb_uio 那么就不需要intel_iommu=on
dmesg | grep -E "DMAR|IOMMU"
查看
-
要利用更快的 x2APIC,需要在内核中打开中断重新映射。这个需要再构建内核时启用
CONFIG_IRQ_REMAP
这个配置项 -
Jailhouse 本身和每个 Cell 都需要一块连续的 RAM,这个必须在 Kernel 启动之前配置。通常是使用
memmap
或mem
这两个启动命令来实现。在 x86 平台上,这通常是在 GRUB 配置文件中通过添加GRUB_CMDLINE_LINUX="memmap=82M\\\$0x3a000000"
这个启动参数来处理。
ARM 架构
针对于 AArch32 架构,需要 Linux Kernel 版本大于等于 3.19;而对于 AArch64 架构,则需要 Linux Kernel 版本大于等于 4.7。此外,还需要适当的的引导程序(例如 U-Boot)的支持。
- Linux Kernel 必须以 HYP 模式启动(工作在 HYP 模式下的 CPU 上,默认是 SVC 模式)。这里就涉及到了 ARM 架构中的不同特权等级,ARMv7 中使用的是 Privilege level 的概念,ARMv8 中则使用 Exception Level 这个概念
- Supervisor Call(SVC)指令使用户模式程序可以请求操作系统服务。
- Hypervisor Call(HVC)指令使客户操作系统能够请求 Hypervisor 服务。
- Secure monitor Call(SMC)指令使普通世界能够请求安全世界服务。
- PSCI 对 CPU 离线的支持。PSCI(Power State Coordination Interface,电源状态协调接口) 是一个接口,这个接口实现了电源管理用例。The ARM Trusted Firmware 实现了 PSCI(Power State Coordination Interface) 接口作为运行时服务。Normal world software 可以通过 ARM SMC(Secure Monitor Call) 指令来访问 ARM Trusted Firmware 服务
- Jailhouse 本身和每个 Cell 都需要一块连续的 RAM,这个必须在 Kernel 启动之前配置。在 ARM 平台上,这可以通过减少内核看到的内存量(通过
mem =
内核启动参数)或修改 Device Tree(即保留内存节点)来实现。
源码
Jailhouse 是由西门子的 Jan Kiszka 在 2013年以 GPLv2 协议开源的一个虚拟化解决方案。并很快得到了官方 Linux 内核的支持,在开源社区中获得了知名度和吸引力。本文及后续博文以目前最新提交(e57d1eff6d55aeed5f977fe4e2acfb6ccbdd7560
)版作为学习对象。
源码文件
Jailhouse 作为一个极度精简的虚拟化实现方案,其代码量还是非常小的,几万行代码量就实现了一个功能强大的虚拟机。
-
.github
和ci
:这两个目录下是用来持续集成环境中使用的构建 Jailhouse 所需的 Linux Kernel 的相关配置文件,目前仅支持 GitHub Actions。 -
config
:这个目录下就是针对arm
、arm64
、x86
架构下用于生成 Jailhouse 的 Cell 的配置文件对应的源文件。在对应架构下构建 Jailhouse 时,对应架构目录下的每个.c
就会被构建为对应的.cell
文件。- 配置文件的内容其实就是一个 C 语言的结构体变量,因此使用的就是
.c
扩展名 - 该目录下的
.c
文件实际上都是一些示例,在真正使用时,我们需要提供自己的配置文件!
- 配置文件的内容其实就是一个 C 语言的结构体变量,因此使用的就是
-
Documentation
:Jailhouse 的文档对应的源码,它使用的是 Doxygen 文档系统。使用sudo apt install doxygen
后,使用命令make docs
就可以在Documentation/generated/
构建出对应的文档。
-
driver
:Jailhouse 的驱动源码,最终会被编译为jailhouse.ko
,并被放到/lib/modules/$(uname -r)/extra/driver/
目录下来使用!cell.c/h
:实现 Cell 相关命令的处理pci.c/h
:实现对 PCI 设备的处理。在将 PCI 设备分配给 Non-root Cell 时,我们需要确保 Root Cell 中的 Linux 不再使用这些设备。只要设备被分配给了其他 Cell ,Root Cell 就不得再访问这些设备。不幸的是,我们不能仅仅使用 PCI 热插拔来在运行时删除/重新添加设备,因为,Linux 将重新编程 BAR(Base Address Registers)并定位到我们不希望/不允许的资源位置。
所以,Jailhouse 充当了一个 PCI 虚拟驱动程序,在其他 Cell 使用设备时它会声明这些设备。在创建 Cell 时,设备将从其驱动程序中解绑,并绑定到 Jailhouse。当 Cell 被销毁时,Jailhouse 将释放其设备。当禁用 Jailhouse 时,它将释放所有已分配的设备。
当释放设备时,它们将不再绑定到任何驱动程序,从 Linux 的角度来看,Jailhouse 虚拟驱动程序仍然会被视为有效的驱动程序。将设备重新分配给原始驱动程序必须手动完成。sysfs.c/h
:还通过 sysfs 虚拟文件系统(/sys/devices/jailhouse
)向用户空间暴露 Jailhouse 的数据结构。main.c/h
:驱动入口
-
hypervisor
:Jailhouse 用于管理各个虚拟机的工具的源码代码,最终会被编译为jailhouse*.bin
,被放到/lib/firmware
目录下arch
:再实际使用中,架构相关的代码先被执行,其中调用架构无关的代码- 其他:架构无关的代码,其中的接口被
arch
中对应的接口调用
-
include
:Jailhouse 对外提供的各种 C 头文件,其中包含了各种数据结构的定义,例如,cell-config.h
中就定义了各种设备的数据结构、Cell 的描述符jailhouse_cell_desc
等等
Jailhouse 允许用户定义一些在编译时启用的特定于平台的设置或者调试配置参数。方法是新增include/courahouse/config.h
这个文件,然后在该文件中将对应的配置项定义为 1。如下是当前可用的配置项:/* Print error sources with filename and line number to debug console */ #define CONFIG_TRACE_ERROR 1/** Set instruction pointer to 0 if cell CPU has caused an access violation.* Linux inmates will dump a stack trace in this case.*/ #define CONFIG_CRASH_CELL_ON_PANIC 1/* Enable code coverage data collection (see Documentation/gcov.txt) */ #define CONFIG_JAILHOUSE_GCOV 1/** Link inmates against a custom base address. Only supported on ARM* architectures. If this parameter is defined, inmates must be loaded to* the appropriate location.*/ #define CONFIG_INMATE_BASE 0x90000000/** Only available on x86. This debugging option that needs to be activated* when running mmio-access tests.*/ #define CONFIG_TEST_DEVICE 1
-
inmates
:这里面是 Jailhouse 虚拟机本身的固件源码,他们会被编译为.bin
文件。demos
:这里面就是一些 inmate 的源码,编译之后就是一个个的 inmate 镜像(.bin
文件)。其都有一个对应的.cell
文件,位于configs/
目录下。lib
:该目录下是一些可以在 inmate 的源码中使用的库函数的实现。tests
:该目录下是一些验证 Jailhouse 的用例tools
:该目录下是一些用来辅助处理 inmate 的工具的源码,每个.c
文件经过编译之后成为一个xxx.bin
,最终所有的.bin
会被安装到/usr/local/libexec/jailhouse
目录下。目前该目录下就只有一个linux-loader
的源码。
-
pyjailhouse
:这里面是用来处理在 Non-root Cell 中运行 Linux 虚拟机时对 Linux Kernel 进行处理的一个 Python 脚本库。 -
scripts
:编译系统使用的相关脚本 -
tools
:这里面是一些 Jailhouse 实用工具(jailhouse
)的源码(其中有些是 Python 脚本)。其中,Python 脚本会被放到/usr/local/libexec/jailhouse
目录下;jailhouse
则被放到/usr/local/sbin
目录下。 -
Makefile
:构建系统的入口 -
Kbuild
:也是个 Makefile 文件 -
setup.py
:用来打包及安装 pyjailhouse 的脚本文件。 -
其他
:其他
构建
Jailhouse 的构建过程非常简单,但是由于不同的平台下的虚拟化技术的差异,在构建时遇到的问题也不一样,受限于博文篇幅,我们将在后续博文中详细学习在不同平台下的构建及使用。
- 虚拟化 之二 详解 jailhouse(x86 平台)的构建过程、配置及使用
- 虚拟化 之三 详解 jailhouse(ARM 平台)的构建过程、配置及使用
基本组件
完整的 Jailhouse 组件主要由内核模块(jailhouse.ko
)、虚拟机管理程序固件(jailhouse*.bin
)、管理工具(jailhouse
命令行程序及一些 Python 脚本)以及配置文件(.cell
)这四部分组成。用户使用它们来启用虚拟机管理程序、创建 Cell、加载 inmate 二进制文件以及运行和停止它等。
jailhouse.ko
jailhouse.ko
由源码根目录中的 driver
目录中源码在构建之后生成,最终会被安装到 /lib/modules/$(uname -r)/extra/driver/
目录下。它就是一个标准的 Linux Driver 程序,实现为一个 struct miscdevice
设备(主设备号 MISC_MAJOR(10)
)。使用命令 cat /proc/misc
可以查看各杂项设备。
Linux 中将设备分为字符设备(I2C、USB、SPI等)、块设备(存储器相关的设备如EMMC、SD卡、U盘等)和网络设备(网络相关的设备WIFI等)三大类,其中,杂项设备归属于字符设备。每个设备节点都有主设备号和次设备号 ,杂项设备的主设备号固定为10,次设备号根据设备不同而不同。
jailhouse_init()
当加载 jailhouse.ko
之后,驱动源码 driver/main.c
中的 static int __init jailhouse_init(void)
函数就会进行各种初始化,主要就干了以下几个事:
- 开头的这一堆的宏定义主要就是为了解决 Jailhouse 用的一些符号 Linux Kernel 没有导出的问题。其核心就是通过
kallsyms_lookup_name
这个内核接口来查找需要的符号。
但是,5.7.0 以上版本的内核不再导出 kallsyms_lookup_name,对于在高版本内核不在导出的原因请参考 https://lwn.net/Articles/813350/。实际上,在 5.7.0 以上仍旧可以用struct kprobe
来获取kallsyms_lookup_name
函数的地址,然后再进一步获取到想要的符号。 - 通过
root_device_register("jailhouse")
创建/sys/devices/jailhouse
这个设备,然后调用jailhouse_sysfs_init(jailhouse_dev)
初始化其中的内容,此后,用户空间就可以通过/sys/devices/jailhouse
访问 Jailhouse 的数据结构。zcs@zcs-MassDatas-GXXA203:~/WORKSPACE/Jailhouse/jailhouse$ tree -L 3 -p /sys/devices/jailhouse /sys/devices/jailhouse ├── [drwxr-xr-x] cells # 这个目录中包含了我们创建的那些 Cell 的信息 │ ├── [drwxr-xr-x] 0 # 这个是 Cell 的 ID,Root Cell 的 ID 为 0,后续每创建一个 Cell ,ID 自动增 1 │ │ ├── [-r--r--r--] cpus_assigned # 这个是我们在 Cell 的配置文件中分配给 Cell 的 CPU 原始的配置参数(按位使用置 1 表示使用,例如,fffb) │ │ ├── [-r--r--r--] cpus_assigned_list # 这个是分配给 Cell 的 CPU 的方便我们阅读的列表。例如 0-1,3-15 │ │ ├── [-r--r--r--] cpus_failed # 这个是分配给 Cell 的 CPU 中失败的那些 │ │ ├── [-r--r--r--] cpus_failed_list # 这个是分配给 Cell 的 CPU 中失败的那些的列表 │ │ ├── [-r--r--r--] name # Cell 的名字 │ │ ├── [-r--r--r--] state # Cell 的状态。"running", "running/locked", "shut down", 或 "failed" 之一 │ │ └── [drwxr-xr-x] statistics # Cell 的统计数据 │ │ ├── [drwxr-xr-x] cpu0 │ │ ├── [drwxr-xr-x] cpu1 │ │ ├── [drwxr-xr-x] cpu10 │ │ ├── [drwxr-xr-x] cpu11 │ │ ├── [drwxr-xr-x] cpu12 │ │ ├── [drwxr-xr-x] cpu13 │ │ ├── [drwxr-xr-x] cpu14 │ │ ├── [drwxr-xr-x] cpu15 │ │ ├── [drwxr-xr-x] cpu3 │ │ ├── [drwxr-xr-x] cpu4 │ │ ├── [drwxr-xr-x] cpu5 │ │ ├── [drwxr-xr-x] cpu6 │ │ ├── [drwxr-xr-x] cpu7 │ │ ├── [drwxr-xr-x] cpu8 │ │ ├── [drwxr-xr-x] cpu9 # 以上这些是分配给当前 Cell 使用的所有逻辑 CPU。每个 CPU 节点展开后的内容和下面这些是一样,只不过表示的是单个 CPU 的,下面这些是以上所有 CPU 的汇总 │ │ ├── [-r--r--r--] vmexits_cpuid │ │ ├── [-r--r--r--] vmexits_cr │ │ ├── [-r--r--r--] vmexits_exception │ │ ├── [-r--r--r--] vmexits_hypercall │ │ ├── [-r--r--r--] vmexits_management │ │ ├── [-r--r--r--] vmexits_mmio │ │ ├── [-r--r--r--] vmexits_msr_other │ │ ├── [-r--r--r--] vmexits_msr_x2apic_icr │ │ ├── [-r--r--r--] vmexits_pio │ │ ├── [-r--r--r--] vmexits_total # 全部 CPU 上发生的 VM Exits 总次数,其他的 _xxx 则表示由于 xxx 原因产生的 VM Exits 数量。例如,vmexits_xapic 就表示由于 xapic 产生的 VM Exits 次数 │ │ ├── [-r--r--r--] vmexits_xapic │ │ └── [-r--r--r--] vmexits_xsetbv │ └── [drwxr-xr-x] 1 # 第二个 Cell,其中的内容与上面的一样 │ ├── [-r--r--r--] cpus_assigned │ ├── [-r--r--r--] cpus_assigned_list │ ├── [-r--r--r--] cpus_failed │ ├── [-r--r--r--] cpus_failed_list │ ├── [-r--r--r--] name │ ├── [-r--r--r--] state │ └── [drwxr-xr-x] statistics │ ├── [drwxr-xr-x] cpu2 # 分配给当前 Cell 使用的所有逻辑 CPU。每个 CPU 节点展开后的内容和下面这些是一样 │ ├── [-r--r--r--] vmexits_cpuid │ ├── [-r--r--r--] vmexits_cr │ ├── [-r--r--r--] vmexits_exception │ ├── [-r--r--r--] vmexits_hypercall │ ├── [-r--r--r--] vmexits_management │ ├── [-r--r--r--] vmexits_mmio │ ├── [-r--r--r--] vmexits_msr_other │ ├── [-r--r--r--] vmexits_msr_x2apic_icr │ ├── [-r--r--r--] vmexits_pio │ ├── [-r--r--r--] vmexits_total # 全部 CPU 上发生的 VM Exits 总次数,其他的 _xxx 则表示由于 xxx 原因产生的 VM Exits 数量 │ ├── [-r--r--r--] vmexits_xapic │ └── [-r--r--r--] vmexits_xsetbv ├── [-r--r--r--] console # 这个是 Jailhouse 的终端,我们可以从中直接读取 Jailhouse 的 Log ├── [-r--------] core # 这里面是 Jailhouse 固件以及配置信息,可以使用 tools/jailhouse-gcov-extract 来解析。访问时,确保是 `jailhouse disable` 状态! ├── [-r--r--r--] enabled # 指示 Jailhouse 是否启用。 1 表示启用,0 表示未启用 ├── [-r--r--r--] mem_pool_size # 内存池中的页数 ├── [-r--r--r--] mem_pool_used # 内存池中已用的页数 ├── [lrwxrwxrwx] module -> ../../module/jailhouse # 这是一个由内核机制自动创建的符号链接,指向当前目录的所有者(创建者) ├── [drwxr-xr-x] power # 这个是与电源管理相关的内容 │ ├── [-rw-r--r--] async │ ├── [-rw-r--r--] autosuspend_delay_ms │ ├── [-rw-r--r--] control │ ├── [-r--r--r--] runtime_active_kids │ ├── [-r--r--r--] runtime_active_time │ ├── [-r--r--r--] runtime_enabled │ ├── [-r--r--r--] runtime_status │ ├── [-r--r--r--] runtime_suspended_time │ └── [-r--r--r--] runtime_usage ├── [-r--r--r--] remap_pool_size # 重映射池中的页数 ├── [-r--r--r--] remap_pool_used # 重映射池中已用的页数 └── [-rw-r--r--] uevent # 各种事件
- Root 设备是一个虚拟设备,以该 Root 设备为父设备调用
kobject_create_and_add
就可以让其他设备可以挂在它的下面 - 其中有些节点需要在执行相应的命令后才会有具体的内容
- Root 设备是一个虚拟设备,以该 Root 设备为父设备调用
- 通过
misc_register(&jailhouse_misc_dev);
注册struct miscdevice
设备。加载驱动之后,就会创建/dev/jailhouse
这个设备。用户空间的 Jailhouse 的管理工具使用ioctl()
系统调用通过jailhouse.ko
创建的/dev/jailhouse
这个文件向jailhouse.ko
发送各种请求。 - 调用
jailhouse_pci_register()
将自身注册为一个虚拟的 PCI 设备驱动程序,以便它可以获取分配的设备。 - 调用
register_reboot_notifier(&jailhouse_shutdown_nb);
注册重启回调接口,当内核出现Kernel Halt、Kernel Restart 或 Kernel Power Off
时,就会调用我们注册的回调函数。Jailhouse 注册之后主要用来关闭自身!
jailhouse_ioctl()
各种请求通过内核最终到达 driver/main.c
中的 jailhouse_ioctl
这个函数。static long jailhouse_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
这个函数解析收到的请求,然后调用对应的接口来进一步处理。
static long jailhouse_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
{long err;switch (ioctl) {case JAILHOUSE_ENABLE:err = jailhouse_cmd_enable((struct jailhouse_system __user *)arg);break;case JAILHOUSE_DISABLE:err = jailhouse_cmd_disable();break;case JAILHOUSE_CELL_CREATE:err = jailhouse_cmd_cell_create((struct jailhouse_cell_create __user *)arg);break;case JAILHOUSE_CELL_LOAD:err = jailhouse_cmd_cell_load((struct jailhouse_cell_load __user *)arg);break;case JAILHOUSE_CELL_START:err = jailhouse_cmd_cell_start((const char __user *)arg);break;case JAILHOUSE_CELL_DESTROY:err = jailhouse_cmd_cell_destroy((const char __user *)arg);break;default:err = -EINVAL;break;}return err;
}
jailhouse*.bin
jailhouse*.bin
是由源码根目录中的 hypervisor
目录中的源码在构建之后会生成,针对不同的架构名字会有些区别(它最终会被安装到 /lib/firmware
目录下)。jailhouse*.bin
接收 jailhouse.ko
发来的超级调用,用于硬件资源的分配。
内存布局
jailhouse*.bin
是一个具体特定结构的二进制文件,在 jailhouse*.bin
的开头是一个 struct jailhouse_header
结构。这个 BIN 文件中的部分内容是在构建时就填充好的,还有一部分是在驱动加载它时有驱动程序动态填充的。如下是 jailhouse*.bin
在内存中的布局:
.header
定义于 hypervisor/setup.c
中,并被链接文件强制放到了 BIN 的开头。链接脚本文件 hypervisor.lds
会再构建时被构建系统根据hypervisor/hypervisor.lds.S
自动创建生成(就是简单的展开各种宏(架构不同,宏值不同))。
JAILHOUSE_BASE
JAILHOUSE_BASE
是 jailhouse*.bin
的链接地址,它的具体值被定义到了 hypervisor/arch
中不同架构的 jailhouse_header.h
中。针对同一架构,它一个固定的虚拟地址。
-
x86平台反汇编
objdump --source --all-headers --demangle --line-numbers --wide hypervisor/hypervisor-intel.o > hypervisor/hypervisor-intel.lst
查看
-
ARM64 平台反汇编
aarch64-none-linux-gnu-objdump --source --all-headers --demangle --line-numbers --wide hypervisor/hypervisor.o > hypervisor/hypervisor.lst
查看
入口点
jailhouse*.bin
本身不是一个可以直接运行的程序,所以它没有显示定义入口点。作为虚拟机管理程序,它本身来处理虚拟化相关的问题。无论何种架构,都是通过特定架构 hypervisor/arch/*/entry.S
中的 int arch_entry(unsigned int cpu_id)
这个接口来开启虚拟化配置。
arch_entry()
arch_entry()
函数必须在每个在线的 CPU 上被调用,以便将系统控制权交给 Jailhouse。Jailhouse 将等待指定数量(由 struct jailhouse_header
中的 .online_cpus
指定)的 CPU 都完成初始化,并且在所有启动初始化的 CPU 都完成之前,该函数不会返回。在虚拟机监控程序激活期间未初始化的 CPU 在 Jailhouse 再次停用之前不能被任何单元使用。
- 函数原型:
int arch_entry(unsigned int cpu_id)
- 参数:
- cpu_id:调用方 CPU 的唯一逻辑 ID
- 返回值:0 表示成功;其他值表示失败,通常取值如下:
-EIO (-5)
:lacking hardware capabilities or unsupported hardware state (as configured by Linux)-ENOMEM (-12)
: insufficient hypervisor-internal memory-EBUSY (-16)
: a required hardware resource is already in use-ENODEV (-19)
: CPU or I/O virtualization unit missing-EINVAL (-22)
: invalid system configuration-ERANGE (-34)
: a resource ID is out of supported range
对于一次初始化尝试,初始化函数将始终在所有 CPU 上返回相同的代码。
entry()
arch_entry()
内部最终通过调用定义于 hypervisor/setup.c
中的架构无关的 int entry(unsigned int cpu_id, struct per_cpu *cpu_data)
函数最终实现启动虚拟化功能。
Hypervisor 与 Cell 间接口
Jailhouse 虚拟机管理程序在运行时提供了三种与 Cell 交互的接口。第一种是只读检测接口。第二种是一组超调用,Cell 可以通过执行特定于体系结构的指令来同步调用这些超调用,从而切换到 Hypervisor 模式。第三种接口由位于每个 Cell 内存区域中的变量组成,该内存区域在 Hypervisor 和特定 Cell 之间共享。
只读检测接口
这种接口对于那些不仅仅在 Jailhouse 的 Cell 内部工作的 Cell 代码非常有用。该 ABI 是特定于体系结构的,到目前为止,它仅适用于 x86 架构。在 x8 6架构上,Jailhouse 在执行 cpuid
指令时修改返回的寄存器值如下所示:
Hypercalls
超调用通常通过指定的指令发出,该指令会导致从客户模式切换到虚拟机管理程序模式。在引起模式切换之前,Cell 必须在预定义的寄存器或已知的内存位置准备好调用的参数。完成的超调用的返回码通过类似的通道传递。超调用 ABI 的详细信息是特定于体系结构的,将在以下部分中定义。
这些调用会由定义于 hypervisor/control.c
中的 long hypercall(unsigned long code, unsigned long arg1, unsigned long arg2)
来进行分发然后进一步来处理。
long hypercall(unsigned long code, unsigned long arg1, unsigned long arg2)
{struct per_cpu *cpu_data = this_cpu_data();cpu_data->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL]++;switch (code) {case JAILHOUSE_HC_DISABLE:return hypervisor_disable(cpu_data);case JAILHOUSE_HC_CELL_CREATE:return cell_create(cpu_data, arg1);case JAILHOUSE_HC_CELL_START:return cell_start(cpu_data, arg1);case JAILHOUSE_HC_CELL_SET_LOADABLE:return cell_set_loadable(cpu_data, arg1);case JAILHOUSE_HC_CELL_DESTROY:return cell_destroy(cpu_data, arg1);case JAILHOUSE_HC_HYPERVISOR_GET_INFO:return hypervisor_get_info(cpu_data, arg1);case JAILHOUSE_HC_CELL_GET_STATE:return cell_get_state(cpu_data, arg1);case JAILHOUSE_HC_CPU_GET_INFO:return cpu_get_info(cpu_data, arg1, arg2);case JAILHOUSE_HC_DEBUG_CONSOLE_PUTC:if (!CELL_FLAGS_VIRTUAL_CONSOLE_PERMITTED(cpu_data->public.cell->config->flags))return trace_error(-EPERM);printk("%c", (char)arg1);return 0;default:return -ENOSYS;}
}
通信区域
通信区域是一个每个单元内的内存区域,默认情况下,虚拟机管理程序和特定单元都可以对其进行读写。这是一种可选的通信机制。如果某个单元需要使用该区域,则必须通过其配置将该区域映射到单元的地址空间。如果单元配置为在通信区域方面是被动的(单元标志 JAILHOUSE_CELL_PASSIVE_COMMREG
)并且该区域已被映射,那么必须在单元配置中将其声明为只读。
管理工具
管理工具主要由源码 tools
目录下的 jailhouse.c
在构建之后生成的 jailhouse
可执行程序以及该目录下的一些 Python 脚本 jailhouse-*
组成。jailhouse
会被放到 /usr/local/sbin/jailhouse
目录下,而那些 Python 脚本最终会被安装到 usr/local/libexec/jailhouse
目录下。
可执行程序 jailhouse
jailhouse
这个可执行程序就是所有管理命令的入口,它就是一个标准的用户空间 Linux C 程序。当我们执行 Jailhouse 命令时,命令首先来到了 tools/jailhouse.c
的 int main(int argc, char *argv[])
函数,它负责解析传入的各个选项及参数,然后调用相应的接口进一步处理。
int main(int argc, char *argv[])
{int fd;int err;if (argc < 2)help(argv[0], 1);if (strcmp(argv[1], "enable") == 0) {err = enable(argc, argv);} else if (strcmp(argv[1], "disable") == 0) {fd = open_dev();err = ioctl(fd, JAILHOUSE_DISABLE);if (err)perror("JAILHOUSE_DISABLE");close(fd);} else if (strcmp(argv[1], "cell") == 0) {err = cell_management(argc, argv);} else if (strcmp(argv[1], "console") == 0) {err = console(argc, argv);} else if (strcmp(argv[1], "config") == 0 ||strcmp(argv[1], "hardware") == 0) {call_extension_script(argv[1], argc, argv);help(argv[0], 1);} else if (strcmp(argv[1], "--version") == 0) {printf("Jailhouse management tool %s\n", JAILHOUSE_VERSION);return 0;} else if (strcmp(argv[1], "--help") == 0) {help(argv[0], 0);} else {help(argv[0], 1);}return err ? 1 : 0;
}
Python 脚本 jailhouse-*
对于那些 Python 脚本,我们也不直接使用,而是则由 jailhouse
来帮我们调用的。具体就在 tools/jailhouse.c
中的 static void call_extension_script(const char *cmd, int argc, char *argv[])
函数中通过 Linux 系统的进程调用函数 execvp
来实现。
static void call_extension_script(const char *cmd, int argc, char *argv[])
{const struct extension *ext;char new_path[PATH_MAX];char script[64];if (argc < 3)return;for (ext = extensions; ext->cmd; ext++) {if (strcmp(ext->cmd, cmd) != 0 ||strcmp(ext->subcmd, argv[2]) != 0)continue;snprintf(new_path, sizeof(new_path), "PATH=%s:%s:%s",dirname(argv[0]), JAILHOUSE_EXEC_DIR,getenv("PATH") ? : "");putenv(new_path);snprintf(script, sizeof(script), "jailhouse-%s-%s",cmd, ext->subcmd);execvp(script, &argv[2]);perror("execvp");exit(1);}
}
jailhouse-gcov-extract
Jailhouse 支持在运行时收集代码覆盖率信息(gcov)。gcov(GNU Coverage) 是一个测试代码覆盖率的工具,工作原理是基于代码插桩(code instrumentation)技术。在编译源代码时,通过添加 -ftest-coverage
和 -fprofile-arcs
选项这两个 GCC 编译器选项,编译器会在生成的可执行文件中插入特殊的监控代码。这些监控代码将跟踪源代码中的每个执行路径,并记录下来它们被执行的次数。
- 为了使用该特性,必须新建
include/jailhouse/config.h
文件,并在文件中将CONFIG_JAILHOUSE_GCOV
定义为 1 - 首先正常运行一个 Jailhouse 虚拟机,最后
sudo jailhouse disable
禁用 Jailhouse,但是不要卸载jailhouse.ko
- 执行
./tools/jailhouse-gcov-extract
提取数据生成*.gcda
文件 - 使用其他上层工具(例如,
lcov
)来处理生成*.gcda
文件即可
配置文件
在 Jailhouse 中,所有的 Cell 的硬件资源必须是静态分配的。因此,在启动 Cell 之前,我们必须要有一个配置文件,这个配置文件告诉 Jailhouse 每个 Cell 可以使用哪些硬件资源。
Jailhouse 采用以 .cell
为扩展名的二进制文件作为配置文件,而 .cell
文件是由一个包含一个 C 语言结构体变量来描述硬件资源的 .c
文件生成的。而我们需要根据 Jailhouse 给出的一些示例(configs
)目录下书写自己的 .c
文件,并进一步编译为 .cell
文件来使用。
- 使用命令
jailhouse config check [-h] SYSCONFIG [CELLCONFIG [CELLCONFIG ...]]
可以检查我们的配置文件
SYSCONFIG
SYSCONFIG(全局配置文件)就是 Root Cell 对应的配置文件,它告诉 Jailhouse 当前系统下所有可用的资源有哪些。当我们执行 jailhouse enable SYSCONFIG
时,Jailhouse 就会将 SYSCONFIG 中描述符的资源放到 Root Cell 中。
- 对于 x86 架构,Jailhouse 提供了
sudo jailhouse hardware check
命令来自动检测当前系统配置,并提供了sudo jailhouse config create sysconfig.c
(sysconfig.c
名字可自定义) 来自动生成针对当前系统的配置文件。 - 注意,通过以上命令生成的
sysconfig.c
文件的用户是 root,我们可以使用命令sudo chown zcs:zcs sysconfig.c
更改为自己的用户名和用户组,这样再后续编辑是比较方便。
我们需要将生成的 sysconfig.c
文件放在 Jailhouse 源码的 configs/x86/
目录中,重新构建 Jailhouse 时,构建系统会将自动为其中的 .c
生成一个相应的 .cell
文件。
CELLCONFIG
CELLCONFIG(CELL 配置文件)就是 Non-root Cell 使用的配置文件,定义了 Non-root Cell 可以使用的物理资源,当我们创建 Non-root Cell 时,Jailhouse 就会根据 Non-root Cell 的配置文件,从全局配置文件(Root Cell)中分离出指定的资源。
对于 Non-root Cell 的配置文件需要参考 configs
目录下对应架构下的 .c
文件来手动创建。同样,写好的 .c
文件需要放到 configs/x86/
目录中,重新构建 Jailhouse 时,构建系统会将自动为其中的 .c
生成一个相应的 .cell
文件。
虚拟机固件
Jailhouse 虚拟机中运行的系统镜像或者是一个裸机程序固件被称为 inmate,目前可以是 Linux、FreeRTOS、ERIKA3 RTOS、Zephyr 其中之一。对于 Linux,Jailhouse 无法运行未经修改的 Linux 内核!
参考
- https://software-dl.ti.com/processor-sdk-linux/esd/docs/06_03_00_106/linux/Foundational_Components/Virtualization/Jailhouse.html
- https://www.elecfans.com/d/2338769.html
- https://variwiki.com/index.php?title=Jailhouse_Guide
- https://blog.csdn.net/v6543210/article/details/113890847
- https://www.21ic.com/a/933932.html
- https://blog.csdn.net/v6543210/article/details/118031563
- https://www.21ic.com/a/933932.html
相关文章:
虚拟化 之一 详解 jailhouse 架构及原理、软硬件要求、源码文件、基本组件
Jailhouse 是一个基于 Linux 实现的针对创建工业级应用程序的小型 Hypervisor,是由西门子公司的 Jan Kiszka 于 2013 年开发的,并得到了官方 Linux 内核的支持,在开源社区中获得了知名度和吸引力。 Jailhouse Jailhouse 是一种轻量级的虚拟化…...
汇凯金业:黄金期货交易时间规则
黄金期货交易时间规则因交易所不同而有所差异。以下是几个主要交易所的黄金期货交易时间及其相关规则: 一、纽约商品交易所(COMEX) 纽约商品交易所(COMEX)是全球最大的黄金期货交易市场之一,其黄金期货交易时间如下: 电子交易时间(通过CME…...
LogicFlow 学习笔记——4. LogicFlow 基础 边 Edge
边 Edge 和节点一样,LogicFlow 也内置一些基础的边。LogicFlow 的内置边包括: 直线 - line直角折现 - polyline贝塞尔曲线 - bezier 新建 src/views/Example/LogicFlow/Example08.vue 并编写如下代码: <script setup lang"ts&quo…...
QPS、TPS、并发量、PV、UV
QPS、TPS、并发量、PV、UV 目录 QPS、TPS、并发量、PV、UVQPS(Queries Per Second)TPS (Transactions Per Second)并发量 (Concurrency)PV (Page Views)UV (Unique Visitors) QPS(Queries Per Second) 含义:每秒查询率应用场景:常用于计算机中各类搜索引…...
深中通道通车在即,苏州金龙新V系穿梭巴士引领大湾区交通发展新篇章
深中通道,总投资500亿元,历时七年建成的世界级跨海工程,即将投入运营。该桥连接深圳、中山,全长24公里,通过“桥、岛、隧、水下互通”设计,克服地域障碍。桥面“穿梭巴士”同步启动,提供24小时跨…...
集成学习 #数据挖掘 #Python
集成学习是一种机器学习方法,它通过结合多个模型的预测结果来提高整体性能和稳定性。这种方法的主要思想是“集合智慧”,通过将多个模型(比如决策树、随机森林、梯度提升机等)的预测集成起来,可以减少单个模型的过拟合…...
IDEA 中设置 jdk 的版本
本文介绍一下 IDEA 中设置 jdk 版本的步骤。 一共有三处需要配置。 第一处 File --> Project Structure Project 和 Modules 下都需要指定一下。 第二处 File --> Settings 第三处 运行时的配置...
AI日报|Luma推出AI视频模型,又一Sora级选手登场?SD3 Medium发布,图中文效果改善明显
文章推荐 AI日报|仅三个月就下架?微软GPT Builder出局AI竞争赛;马斯克将撤回对奥特曼的诉讼 谁是最会写作文的AI“考生”?“阅卷老师”ChatGPT直呼惊艳! ⭐️搜索“可信AI进展“关注公众号,获取当日最新…...
嵌入式系统复习(一)
第一章 嵌入式系统的定义、特点 嵌入式系统是以应用为中心,以计算机技术为基础,软件硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。 特点:嵌入性 专用性 计算机系统 嵌入式系统典型组成…...
一次搞定:Java中数组拷贝VS数组克隆
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一…...
Java多线程编程与并发处理
引言 在现代编程中,多线程和并发处理是提高程序运行效率和资源利用率的重要方法。Java提供了丰富的多线程编程支持,包括线程的创建与生命周期管理、线程同步与锁机制、并发库和高级并发工具等。本文将详细介绍这些内容,并通过表格进行总结和…...
C++ 35 之 对象模型基础
#include <iostream> #include <string.h> using namespace std;class Students05{ public:// 只有非静态成员变量才算存储空间,其他都不算int s_a; // 非静态成员变量,算对象的存储空间double s_c;// 成员函数 不算对象的存储空间void f…...
PHP超级全局变量:功能、应用及最佳实践
PHP中的超级全局变量(Superglobal Variables)是预定义的数组,它们在脚本的全部作用域内都可以访问,无需使用global关键字。超级全局变量包含了关于请求、会话、服务器等各种信息,常见的有$_GET、$_POST、$_REQUEST、$_…...
python在windows创建的文件,换成linux系统格式
python在windows创建的文件,换成linux系统格式 dos2unix.exe的下载(下载的文件放入路径下:C:\Windows\System32) 链接:https://pan.baidu.com/s/10fC2tfvUtbh-axJ21cj_Xw?pwdm3zc 提取码:m3zc 批量修改文件格式 import subpr…...
最新区块链论文速读--CCF A会议 ICSE 2024 共13篇 附pdf下载 (2/2)
Conference:International Conference on Software Engineering (ICSE) CCF level:CCF A Categories:Software Engineering/System Software/Programming Languages Year:2024 Num:13 第1~7篇区块链文章请点击此处…...
C++ 34 之 单例模式
#include <iostream> #include <string.h> using namespace std;class King{// 公共的函数,为了让外部可以获取唯一的实例 public:// getInstance 获取单例 约定俗成static King* getInstance(){return true_king;}private: // 私有化// 构造函数设置为…...
SAP BW:传输转换源系统-源系统映射关系
最近有朋友再问问我源系统映射关系怎么配置,想着写一个怕以后忘了。 简单说下这个是干嘛的,其实就是配置一个源系统到目标系统的一个映射,这样传输的时候才知道传过来的数据源要变成目标系统的数据源。 比如下图,在开发环境&…...
React+TS前台项目实战(九)-- 全局常用组件弹窗Dialog封装
文章目录 前言Dialog公共弹窗组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天这篇主要讲全局公共弹窗Dialog组件封装,将用到上篇封装的模态框Modal组件。有时在前台项目中,偶尔要用到一两个常用的组件,如 弹窗&#x…...
利用视觉分析技术提升水面漂浮物、水面垃圾检测效率
随着城市化进程的加速和工业化的发展,水体污染问题日益严重,水面漂浮物成为水环境治理的一大难题。传统的水面漂浮物检测方法主要依赖人工巡查和简单的传感器检测,存在着效率低、准确率不高等问题。为了提升水面漂浮物检测的效率和准确性&…...
NFT 智能合约实战-快速开始(1)NFT发展历史 | NFT合约标准(ERC-721、ERC-1155和ERC-998)介绍
文章目录 NFT 智能合约实战-快速开始(1)NFT发展历史国内NFT市场国内NFT合规性如何获得NFT?如何查询NFT信息?在 OpenSea 上查看我们的 NFT什么是ERC721NFT合约标准ERC-721、ERC-1155和ERC-998 对比ERC721IERC721.sol 接口内容关于合约需要接收 ERC721 资产 onERC721Received…...
Linux知识整理说明
最近学校Linux课程刚刚结课,但还是有其他课程在继续。 所以接下来我会抽时间,根据笔记以及网络资料,整理和Linux相关的知识文档,各位可以后续留意. 完整的章目录我会先发出来,后续补充完整。 所有的内容会在 下周三(6…...
诊所管理系统哪家会好一点
随着医疗行业的快速发展和信息化进程的加速,诊所作为医疗服务的重要基层单位,其运营管理效率与服务质量的提升愈发依赖于现代化的管理工具。诊所管理系统应运而生,旨在通过集成化、智能化的技术手段,帮助诊所实现诊疗流程优化、资…...
前端根据权限生成三级路由
三级菜单和后端返回数组对比获取有权限的路由 数组: //后端返回的数组 const arr1 [sale.management, sale.order, sale.detail]; //前端路由 const arr2 [{path: "/sale-manage",redirect: "/sale-manage/sale-order/sale-list",name: sale…...
Databricks超10亿美元收购Tabular;Zilliz 推出 Milvus Lite ; 腾讯云支持Redis 7.0
重要更新 1. Databricks超10亿美元收购Tabular,Databricks将增强 Delta Lake 和 Iceberg 社区合作,以实现 Lakehouse 底层格式的开放与兼容([1] [2])。 2. Zilliz 推出 Milvus Lite 轻量级向量数据库,支持本地运行;Milvus Lite 复…...
算法day29
第一题 695. 岛屿的最大面积 本题解法:采用bfs的算法; 本题使用象限数组的遍历方法和定义布尔数组vis来遍历每一个元素的上下左右元素,防治被遍历的元素被二次遍历; 本题具体分析如上题故事,但是由于要求区域的最大面…...
车牌识别(附源代码)
完整项目已上传至github:End-to-end-for-chinese-plate-recognition/License-plate-recognition at master duanshengliu/End-to-end-for-chinese-plate-recognition GitHub 整体思路: 1.利用u-net图像分割得到二值化图像 2.再使用cv2进行边缘检测获得车牌区域坐…...
在VSCode中安装python
引言 Python 是一种广泛使用的高级编程语言,因其易学、易用、强大而受到欢迎。它由 Guido van Rossum 于 1991 年首次发布,并以简洁的语法和丰富的库生态系统而著称。 以下是 Python 的一些关键特点和优势: 关键特点 易于学习和使用&#x…...
StarkNet架构之L1-L2消息传递机制
文章目录 StarkNet架构之L1-L2消息传递机制L2 → L1消息L2 → L1消息结构L2 → L1消息哈希L1 → L2消息L1 → L2消息取消L1 → L2报文费用L1 → L2哈希额外资源StarkNet架构之L1-L2消息传递机制 原文地址:https://docs.starknet.io/architecture-and-concepts/network-archit…...
19.2 HTTP客户端-定制HTTP请求、调试HTTP、响应超时
1. 定制HTTP请求 如果需要对向服务器发送的HTTP请求做更多超越于默认设置的定制化。 client : http.Client{} 使用net/http包提供的导出类型Client,创建一个表示客户端的变量。request, err : http.NewRequest("GET", "https://ifconfig.io/ip&quo…...
KafkaQ - 好用的 Kafka Linux 命令行可视化工具
软件效果前瞻 ~ 鉴于并没有在网上找到比较好的linux平台的kafka可视化工具,今天为大家介绍一下自己开发的在 Linux 平台上使用的可视化工具KafkaQ 虽然简陋,主要可以实现下面的这些功能: 1)查看当前topic的分片数量和副本数量 …...
不愧是字节,图像算法面试真细致
这本面试宝典是一份专为大四、研三春招和研二暑假实习生准备的珍贵资料。 涵盖了图像算法领域的核心知识和常见面试题,包括卷积神经网络、实例分割算法、目标检测、图像处理等多个方面。不论你是初学者还是有经验的老手,都能从中找到实用的内容。 通过…...
14、C++中代码重用
1、C模板的主要作用是允许编写通用代码,即能够在不同数据类型或数据结构上工作而无需重复编写代码。通过模板,可以实现代码的复用性和灵活性,从而提高开发效率和程序的可维护性。 typename关键字: 在C中,typename关键…...
剖析框架代码结构的系统方法(下)
当面对Dubbo、Spring Cloud、Mybatis等开源框架时,我们可以采用一定的系统性的方法来快速把握它们的代码结构。这些系统方法包括对架构演进过程、核心执行流程、基础架构组成和可扩展性设计等维度的讨论。 在上一讲中,我们已经讨论了架构演进过程和核心执行流程这两个系统方法…...
C语言学习笔记之结构体(一)
目录 什么是结构体? 结构体的声明 结构体变量的定义和初始化 结构体成员的访问 结构体传参 什么是结构体? 在现实生活中的很多事物无法用单一类型的变量就能描述清楚,如:描述一个学生,需要姓名,年龄&a…...
MATLAB入门知识
目录 原教程链接:数学建模清风老师《MATLAB教程新手入门篇》https://www.bilibili.com/video/BV1dN4y1Q7Kt/ 前言 历史记录 脚本文件(.m) Matlab帮助系统 注释 ans pi inf无穷大 -inf负无穷大 i j虚数单位 eps浮点相对精度 0/&a…...
计算机网络(5) ARP协议
什么是ARP 地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定…...
美团的 AI 面试有点简单
刷到一个美团的 AI 实习生的面试帖子,帖子虽然不长,但是把美团 AI 评测算法实习生面试的问题都po出来了。 单纯的看帖子中面试官提出的问题,并不是很难,大部分集中在考察AI项目和对AI模型的理解上,并没有过多的考察AI算…...
编程软件怎么给机器人编程:深入探索编程与机器人技术的融合
编程软件怎么给机器人编程:深入探索编程与机器人技术的融合 随着科技的飞速发展,机器人技术已经深入到我们生活的方方面面。而要让机器人按照我们的意愿执行任务,就需要借助编程软件对机器人进行编程。那么,编程软件究竟是如何给…...
unity2d Ugui--Image城市道路汽车行驶
目录 1.车辆生成与回收 2.路径点控制 3.车辆控制 1.车辆生成与回收 using System.Collections.Generic; using UnityEngine;public class RoadContr : MonoBehaviour {public WayPoint[] wayPoints; //出生点public Transform pare;[SerializeField]private Car[] fabCar;pu…...
【深度学习】【Prompt】使用GPT的一些提示词
f翻译论文用这个提示词: # 翻译规则## 翻译规则1 请在翻译这篇学术论文时,严格保留所有专业术语的原始英文表述,不要尝试将它们翻译成中文,而不是专业术语的部分,需要翻译为中文。保持所有文章引用格式和内容的完整无…...
如何在centos中和windows server中找到挖矿木马和消灭挖矿木马
在 CentOS 和 Windows Server 中查找和消灭挖矿木马涉及多个步骤,包括检测、清理和预防。以下是具体的步骤和命令。 在 CentOS 中查找和消灭挖矿木马 步骤 1:检测木马 检查异常进程: ps aux | grep -E miner|cryptonight|xmrig查找进程列表…...
Slice用法举例Python
Slice用法举例Python 在Python中,slice(切片)是一个强大的工具,用于处理序列类型的数据,如列表、元组、字符串等。slice提供了一种简洁而高效的方式来获取序列的子集或修改序列的某些部分。下面,我们将从四…...
响应式网页开发方法与实践
随着移动设备的普及和多样化,响应式网页开发已成为现代网页设计的主流趋势。响应式网页(Responsive Web Design, RWD)是一种网页设计技术,其核心思想是通过灵活的布局和媒体查询,使网页能够适应不同设备和屏幕尺寸&…...
feedparser - Python 解析Atom和RSSfeed
文章目录 一、关于 feedparser二、安装三、关于文档及构建四、测试五、常见RSS元素访问常见 Channel 元素访问常用项目元素 六、常见Atom元素访问常用feed元素访问公共入口元素 七、获取Atom元素的详细信息Feed元素的详细信息 八、测试元素是否存在九、其他功能 & 文档高级…...
ARM32开发--IIC时钟案例
知不足而奋进 望远山而前行 目录 文章目录 前言 目标 内容 需求 开发流程 移植驱动 修改I2C实现 测试功能 总结 前言 在现代嵌入式系统开发中,移植外设驱动并测试其功能是一项常见的任务。本次学习的目标是掌握移植方法和测试方法,以实现对开…...
[深度学习]基于C++和onnxruntime部署yolov10的onnx模型
基于C和ONNX Runtime部署YOLOv10的ONNX模型,可以遵循以下步骤: 准备环境:首先,确保已经下载后指定版本opencv和onnruntime的C库。 模型转换:按照官方源码:https://github.com/THU-MIG/yolov10 安装好yolov…...
Spring-事件
Java 事件/监听器编程模型 设计模式-观察者模式的拓展 可观察者对象(消息发送者) Java.util.Observalbe观察者 java.util.Observer 标准化接口(标记接口) 事件对象 java.util.EventObject事件监听器 java.util.EventListener public class ObserverDemo {public static vo…...
delmia的工序设置
process的设置需要在workcell sequuencing里面去设置...
【JavaEE精炼宝库】多线程(5)单例模式 | 指令重排序 | 阻塞队列
目录 一、单例模式: 1.1 饿汉模式: 1.2 懒汉模式: 1.2.1 线程安全的懒汉模式: 1.2.2 线程安全的懒汉模式的优化: 二、指令重排序 三、阻塞队列 3.1 阻塞队列的概念: 3.2 生产者消费者模型…...
[图解]《分析模式》漫谈03-Party是什么
1 00:00:00,790 --> 00:00:03,930 今天我们来看一下,Party是什么 2 00:00:05,710 --> 00:00:07,470 当然我们这里说的不是政治的 3 00:00:07,880 --> 00:00:08,350 Party 4 00:00:09,230 --> 00:00:11,110 是《分析模式》里面的一个用词 5 00:00:14…...