KVM/ARM——基于ARM虚拟化扩展的VMM

1. 前言

ARM架构为了支持虚拟化做了些扩展,称为虚拟化扩展(Virtualization Extensions)。原先为VT-x创建的KVM(Linux-based Kernel Virtual Machine)适配了ARM体系结构,引入了KVM/ARM (the Linux ARM hypervisor)。KVM/ARM没有在hypervisor中引入复杂的核心功能,而是利用了Linux内核中现有的功能进行适配。KVM/ARM与Linux集成,在可移植性和硬件支持方面会有所收益。其实也可以开发独立的bare metal hypervisor,这样可能会有更好地性能,但这种方法在ARM上不太好使。

在下面,我们将描述KVM/ARM的设计如何使得它可以从现有kernel的集成中获益,同时利用硬件虚拟化特性。

2. Split-mode虚拟化

KVM/ARM利用了现有的kernel功能,例如调度器(scheduler),但KVM/ARM如果直接在EL2中运行Linux kernel,会存在两个问题。

第一,linux中与底层体系结构相关的代码是为在kernel模式下工作而编写的,不经过修改就不能在EL2中运行,因为EL2是一个完全不同于普通kernel模式的CPU模式。Linux kernel社区不太可能接受在EL2中运行kernel所需的重大更改。更重要的是,为了保持与没有EL2的硬件的兼容性并将Linux作为Guest OS运行,必须编写低级代码以在两种模式下工作,这可能会导致缓慢而复杂的代码路径。举个简单的例子,页表错误处理程序需要获取导致页表错误的虚拟地址。在EL2中,这个地址存储在与kernel模式不同的寄存器中。

第二,在EL2中运行整个内核会对本机性能产生不利影响。例如,EL2有自己独立的地址空间,但是kernel模式使用两个页表基本寄存器(TTBR)在user地址空间和kernel地址空间之间提供熟悉的3GB/1GB分割,而EL2使用单个页表寄存器,因此不能直接访问地址空间的user空间部分。经常使用的访问user内存的函数需要kernel显式地将用户空间数据映射到kernel地址空间,然后执行必要的拆解和TLB维护操作,从而导致ARM的性能不好。

综上所述,KVM/ARM引入了split-mode虚拟化,这种一种新的hypervisor设计方法,它将核心hypervisor分开,以便它可以跨不同的特权CPU模式运行,从而利用每种CPU模式提供的特定优势和功能。KVM/ARM使用split-mode虚拟化来利用EL2支持的ARM硬件虚拟化,同时利用在kernel模式下运行的现有Linux kernel服务。Split-mode虚拟化允许KVM/ARM与Linux kernel集成,而无需对现有代码库进行重大修改。

这是通过将hypervisor分成两个组件来实现的:lowvisor和highvisor,如图1所示。

图1 KVM/ARM系统架构

Lowvisor的设计是利用EL2中提供的硬件虚拟化支持来提供三个关键功能。首先,lowvisor通过适当的硬件配置来设置正确的执行上下文,并在不同的执行上下文之间实施保护和隔离。Lowvisor直接与硬件保护功能交互,因此非常关键,且代码库需要保持绝对最小。其次,lowvisor从VM执行上下文切到到host执行上下文,反之亦然。Host执行上下文用于运行hypervisor和host Linux kernel。我们将执行上下文称为一个世界,将从一个世界切换到另一个世界称为世界切换(world switch),因为系统的整个状态都发生了变化。由于lowvisor是唯一在EL2中运行的组件,因此只有它可以负责执行世界切换所需的硬件重新配置。第三,lowvisor提供了一个虚拟化Trap处理程序,它处理必须Trap到hypervisor的中断和异常。所有发送到hypervisor的Trap必须首先发送到lowvisor。在世界切换到highvisor完成后,lowvisor只执行所需的最少量的处理,并将要完成的大部分工作推迟到highvisor。

Highvisor作为host linux kernel的一部分在kernel模式下运行。因此,它可以直接利用现有的linux功能,例如调度器,并且可以利用标准的kernel软件数据结构和机制来实现其功能,例如locking机制和memory分配功能。它使高层功能更容易在highvisor中实现。例如,虽然lowvisor提供低级Trap处理程序和低级机制来从一个世界切换到另一个世界,但highvisor处理来自VM和的stage-2页表错误并执行指令仿真。请注意,部分VM以kernel模式运行,就像highvisor一样,但是启用了stage-2转换和Trap到EL2。

因为hypervisor在kernel模式和EL2之间是分开的,所以在VM和highvisor之间的切换涉及到多个模式转换。在运行VM时,向highvisor发出Trap将首先向EL2中lowvisor发出Trap。然后lowvisor将发起另一个Trap去运行highvisor。类似地,从highvisor切换到VM需要从kernel模式切换到EL2,然后切换到VM。因此,在切换到或切换出highvisor时,split-mode虚拟化会产生双重Trap成本。在ARM上,执行这些模式转换到EL2或从EL2转换的唯一方法就是通过Trap。不过,这个额外的Trap在ARM上并不是一个显著的性能成本。

KVM/ARM使用内存映射接口根据需要在highvisor和lowvisor之间共享数据。由于内存管理可能很复杂,它利用了linux中现有内存管理子系统的功能来管理highvisor和lowvisor的内存。但是管理lowvisor的内存涉及到额外的挑战,它需要管理EL2的单独地址空间。一种简单的方法是重用host kernel的页表,并在EL2中使用它们来使地址空间相同。不过这样有问题,因为EL2使用和kernel模式不同的页表格式。因此,highvisor显式地管理EL2页表,将在EL2种执行的任何代码以及highvisor和lowvisor之间共享的任何数据结构映射到EL2和kernel模式中的相同虚拟地址。

3. CPU虚拟化

为了虚拟化CPU,KVM/ARM必须向VM提供一个接口,该接口本质上与底层的实际硬件相同,同时确保hypervisor仍然控制硬件。它包括确保在虚拟机中运行的软件必须与在物理CPU上运行的软件具有对相同寄存器状态的一致访问,以及确保切换VM运行中,与hypervisor及其host kernel相关联的物理硬件状态是一致的。为了不影响VM隔离,寄存器状态可以简单地通过保存VM状态和从VM切换到host时从内存恢复主机状态进行上下文切换,反之亦然。KVM/ARM将对所有其它敏感状态的访问配置为Trap到EL2,因此hypervisor可以模拟它。

表1为在kernel模式和user模式下运行的软件可以看到的寄存器状态,以及KVM/ARM对每个寄存器组的虚拟化方法。Lowvisor有自己专用的配置寄存器,仅供EL2使用。只要硬件支持,在世界切换期间,KVM/ARM上下文会切换寄存器,因为它允许VM直接访问硬件。例如,VM可以直接对stage-1页表基本寄存器进行编程,而不需要Trap到hypervisor,这在大多数Guest OS中是相当常见的操作。KVM/ARM在敏感指令和访问硬件状态时执行Trap和模拟,这些状态可能会影响hypervisor或将有关硬件的信息泄漏给VM,违反了虚拟化原理。例如。如果VM执行导致CPU断电的WFI指令,KVM/ARM会Trap,这样的操作应该只由hypervisor执行,以保持对硬件的控制。

表1 VM和Host的状态

在kernel或user模式下运行虚拟机与在kernel或user模式下运行hypervisor之间的区别取决于EL2在世界切换期间如何配置virtualization extensions。从host切换到VM的过程如下:

1.将所有host GP寄存器存到EL2的堆栈中;

2.给VM配置vGIC;

3.给VM配置timers;

4.将所有host特定的配置寄存器存到EL2堆栈中;

5.将VM的配置寄存器加载到硬件,这个操作不会影响当前执行,因为EL2使用它自己的配置寄存器,这些寄存器从host状态中分离出来。

6.配置EL2以Trap浮点操作(VFP寄存器的lazy context switching),trap中断,trap CPU halt指令(WFI/WFE),trap SMC指令,Trap特定配置寄存器访问和trao调试寄存器访问;

7.将虚拟机特定的ID写入shadow ID寄存器中,这由ARM虚拟化扩展定义,并由虚拟机访问,以代替ID寄存器中的硬件值;

8.设置stage-2页表基寄存器(VTTBR)并启用stage-2地址转换;

9.恢复所有guest GP寄存器;

10.进入user模式或kernel模式;

CPU将留在虚拟机世界,直到有event发生,触发进入EL2的trap。这样的事件可能由上面提到的任何Trap、stage-2页表错误或硬件中断引起。由于event需要highvisor的服务,要么模拟虚拟机预期的硬件行为,要么服务于设备中断,KVM/ARM必须执行另一个世界切换到highvisor和它的host。这需要先到lowvisor,然后再到highvisor。从VM世界切换到host世界需要以下步骤:

1.保存所有VM GP寄存器;

2.关闭stage-2转换;

3.配置EL2不Trap任何寄存器访问和指令;

4.保存所有VM特定的配置寄存器;

5.加载host的配置寄存器到硬件;

6.配置host的timers;

7.保存VM特定的vGIC状态;

8.恢复所有host GP寄存器

9.进入kernel模式;

4. 内存虚拟化

如图2所示,ARM提供了stage-2页表来将Guest物理地址转换为host物理地址。KVM/ARM通过启用stage-2转换,为在虚拟机中运行时为所有内存访问提供内存虚拟化。Stage-2转换只能在EL2中配置,它的使用对VM是完全透明的。Highvisor管理stage-2翻译页表,只允许访问专门为VM分配的内存。其它访问将导致stage-2页表错误,从而Trap到hypervisor。该机制确保虚拟机不能访问hypervisor或其它虚拟机的内存,包括任何敏感数据。在highvisor和lowvisor中运行时禁用stage-2转换,因为highvisor完全控制整个系统并直接管理host物理地址。当hypervisor切换到VM时,它启用stage-2转换并相应地配置stage-2页表基寄存器。尽管highvisor和VM共享相同的CPU模式,但stage-2转换确保highvisor不受VM的任何访问。

图2 ARM的两级页表

KVM/ARM是一个split-mode虚拟化来利用现有的kernel内存分配、页表引用计数和页表操作代码。KVM/ARM通过考虑出错的gPA来处理stage-2页表出错,以及该地址是否属于VM内存映射,KVM/ARM通过简单地调用一个现有的kernel函数(如get_user_pages)为VM分配一个页表,并将分配的页表映射到stage-2页表中的VM。

5. I/O虚拟化

KVM/ARM利用现有的QEMU和Virtio user空间设备模拟来提供I/O虚拟化。在硬件层面上,ARM架构上的所有I/O机制都是基于对MMIO设备区域的load/store操作。除了直接分配给VM的设备,所有硬件MMIO区域不能被虚拟机访问。KVM/ARM使用stage-2转换来确保不能从虚拟机直接访问物理设备。在为VM分配的RAM区域之外的任何访问都将被hypervisor Trap,hypervisor可以根据fault地址将访问路由到QEMU中的特定模拟设备。

6. 中断虚拟化

KVM/ARM利用其与Linux的集成来重用现有的设备驱动程序和相关功能,包括处理中断。当在虚拟机中运行时,KVM/ARM配置CPU将所有硬件中断Trap到EL2。在每个中断中,它执行到hypervisor的世界切换,host处理中断,这样hypervisor就可以保留完全控制硬件资源。当在host和highvisor中运行时,中断直接Trap到kernel模式,避免通过EL2的开销。在这两种情况下,所有硬件中断处理都是通过重用Linux现有的中断处理功能在host中完成的。

但是,虚拟机必须以虚拟中断的形式接收来自模拟设备的通知,multicore Guest OSs必须能够从一个虚拟core发送虚拟IPIs到另一个虚拟xore。KVM/ARM通过vGIC向虚拟机注入虚拟中断,减少EL2的Trap数量。通过编程vGIC hypervisor CPU控制接口中的list registers,虚拟中断被提升到虚拟CPU。KVM/ARM配置stage-2页表,来防止虚拟机访问控制接口,只允许访问vGIC虚拟CPU接口,保证只有hypervisor可以编程控制接口,虚拟机可以直接访问vGIC虚拟接口。然而,Guest OS仍然会尝试访问GIC分发器来配置GIC,并讲IPI从一个虚拟core发送到另一个虚拟core。这样的访问将Trap到hypervisor,hypervisor必须模拟分发程序。

KVM/ARM引入了虚拟分发器,这是GIC分发器的一个软件模型,作为highvisor的一部分。虚拟分发器向User空间公开接口,因此user空间中的模拟设备可以向虚拟分发器发起虚拟中断,并向VM公开与物理GIC分发器相同的MMIO接口。虚拟分发器保存关于每个中断状态的内部软件状态,并在调度VM时使用此状态,编程list registers以注入虚拟中断。例如,如果虚拟CPU0向虚拟CPU1发送一个IPI,分发程序将编程虚拟CPU1的list registers以引发一个虚拟IPI中断给虚拟CPU1。

理想情况下,虚拟分发程序只在必要时访问硬件list registers,因为设备MMIO操作通常比cache内存访问慢得多。当调度不同的VM在物理core上运行时,需要list registers的完整上下文切换,但当简单地在VM和hypervisor之间切换时,则不一定需要上下文切换。例如,如果没有挂起的虚拟中断,则不需要访问任何list register。注意,一旦hypervisor在切换到VM时将一个虚拟中断写入一个list register,那么在切换会hypervisor时,它还必须读回这个list register,因为list register描述了虚拟中断的状态。KVM/ARM的初始未优化版本使用了一种简单的方法,该方法完全切换所有vGIC状态,包括每个世界开关上的list register。

7. 计时器虚拟化

读取计数器和编程计时器是许多操作系统中用于进程调度和定期轮询设备状态的常见操作。例如,Linux读取一个计数器来确定进程是否已经过期,并编程计数器来确保进程没有超出其允许的时间片段。由于各种原因,应用程序工作负载也经常使用计时器。为每个这样的操作Trap到hypervisor可能会导致明显的性能开销,并且允许VM直接访问计时硬件通常意味着放弃对硬件资源的定时控制,因为VM可以禁用计时器并在较长的时间内控制CPU。

KVM/ARM利用ARM的通用定时器的硬件虚拟化特性来允许虚拟机直接访问可读计数器和编程计时器,而不会引起Trap到EL2,同时确保hypervisor仍然控制硬件。由于使用EL2控制对物理计时器的访问,因此任何控制EL2模式的软件都可以访问物理计时器。KVM/ARM通过使用hypervisor中的物理计时器和不允许从虚拟机访问物理计时器来维护硬件控制。作为Guest OS运行的Linux kernel只能访问虚拟计时器,因此可以直接访问计时器硬件,而不会被hypervisor Trap住。

不过由于体系结构的限制,虚拟计时器不能直接引发虚拟中断,而总是引发硬件中断,而硬件中断会Trap到hypervisor。KVM/ARM检测虚拟机的虚拟计时器是否到期,并向虚拟机注入相应的虚拟中断,在highvisor中执行所有硬件ACK和EOI操作。硬件只为每个物理CPU提供一个虚拟计时器,多个虚拟CPU可以再这个硬件实例上复用。为了在这种情况下支持虚拟计时器,KVM/ARM在虚拟机进入hypervisor时检测未过期的计时器,并利用现有的OS功能在虚拟计时器本来触发的时候编程一个软件计时器,让虚拟机处于运行状态。当这样的软件计时器触发时,将执行一个回调函数,该函数使用上面描述的虚拟分发器向VM引发一个虚拟计时器中断。

8. ARM体系结构的改进

根据KVM/ARM开发人员的经验,对ARM架构进行了一系列改进,以避免对KVM/ARM等type-2 hypervisor进行split-mode虚拟化的需要。这些改进包括Virtualization Host Extensions(VHE),它现在是ARM 64-bit架构新版本ARMv8.1的一部分。VHE允许将设计在EL1中运行的OS运行在EL2中,而无需对OS源代码进行实质性修改。

VHE是通过添加一个新的控制位E2H来提供的,该位在系统启动时安装使用VHE的type-2 hypervisor是设置的。如果该位没有设置,ARMv8.1在硬件虚拟化方面与ARMv8相同,保留了与现有hypervisor的向后兼容性。如果该位设置了,那么VHE将开启三个主要特性。

首先,VHE扩展了EL2,向CPU添加额外的物理寄存器状态,这样EL1中可用的任何寄存器和功能也可以在EL2中使用。例如,EL1有两个寄存器:TTBR0_EL1和TTBR1_EL1。第一个用于查找页表中较低VA范围内的虚拟地址,第二个用于较高VA范围内的虚拟地址。它提供了一种在user空间和kernel空间之间分隔虚拟空间的方便、高效地方法。但是,如果没有VHE,EL2只有一个页表基寄存器TTBR0_EL2,这使得在EL2中运行时支持EL1的分隔VA空间存在问题。对于VHE,EL2将有第二个页表基寄存器TTBR1_EL2,从而可以支持分隔VA空间EL2的方式与EL1相同。用于启用与host集成的type-2 hypervisor操作系统去支持在EL2种分割VA空间,这是运行EL2种的host OS所必需的,以便管理user空间和kernel之间的VA空间。

其次,VHE提供了一种机制来透明地访问额外的EL2寄存器状态。简单地提供额外的EL2寄存器不足以在EL2中运行未修改的OS,因为现有的操作系统被写入访问EL1寄存器。例如,Linux使用了TTBR1_EL1,不影响EL2种运行的translation系统。提供额外的寄存器TTBR1_EL2仍然需要修改Linux,以便分别在EL2中运行时使用TTBR1_EL2而不是TTBR1_EL1。为了避免迫使OS供应商给软件增加这种额外的复杂性,VHE允许未经修改的软件在EL2种执行,并使用EL1寄存器访问函数指令编码透明的访问EL2寄存器。例如,当前的操作系统软件用指令MRS x1,TTBR1_EL1读取TTBR1_EL1寄存器。对于VHE,软件仍然执行相同的指令,但是硬件实际访问的是TTBR1_EL2寄存器。只要设置了E2H bit,访问EL1寄存器实际上访问了EL2寄存器,从而透明地重写了对EL2的寄存器访问。添加了一组新的特殊指令来访问EL2中EL1寄存器,hypervisor可以使用这些指令在将EL1中运行的VM之间进行切换。例如,如果hypervisor希望访问Guest的TTBR1_EL1,它将使用指令MRS x1,TTBR_EL21。

第三,VHE扩展了EL2的memory translation能力。在ARMv8种,EL2和EL1使用不同的页表格式,因此编写在EL1种运行的软件必须经过修改才能在EL2中运行。在ARMv8.1中,当设置了E2H位时,EL2页表格式现在与EL1格式兼容。因此,以前在EL1中运行的OS现在可以在EL2中运行而无需修改,因为它可以使用相同的EL1页表格式。

图3显示type-1和type-2 hypervisor程序如何映射到具有VHE的体系结构。


图3 虚拟化扩展(VHE)

Type-1 hypervisor(如Xen)可以明确地设计为在EL2中运行,而无序任何额外的支持,它不设置VHE引入的E2H位,并且EL2的行为与ARMv8完全相同。Type-2 hypervisor(如KVM/ARM)在系统启动时设置了E2H位,host OS kernel只在EL2中运行,不会在EL1中运行。Type-2 hypervisor kernel可以在EL2中不加修改地运行,因为VHE为每个EL1寄存器提供了一个等效的EL2寄存器,并透明地将EL1寄存器访问从EL2重写为EL2寄存器访问,而且EL1和EL2之间的页表格式现在是兼容的。从host user空间到host kernel的转换直接从EL0到EL2进行,例如处理系统调用,如图7.4的箭头所示。从VM到hypervisor的转换现在无须上下文切换EL1状态,因为hypervisor不使用EL1。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/68299.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【go语言】数组和切片

一、数组 1.1 什么是数组 数组是一组数:数组需要是相同类型的数据的集合;数组是需要定义大小的;数组一旦定义了大小是不可以改变的。 1.2 数组的声明 数组和其他变量定义没有什么区别,唯一的就是这个是一组数,需要给…

node.js 07.npm下包慢的问题与nrm的使用

一.npm下包慢 因为npm i 默认从npm官网服务器进行下包,但是npm官网服务器是海外服务器所以响应很慢. 于是我们通过npm下包的时候通常用淘宝镜像进行下包,下面是切换到淘宝镜像地址下包的操作. 二.nrm的使用 nrm是一个管理切换npm下包地址的工具,可以快速切换下包的地址. 安…

Windows10官方系统下载与安装保姆级教程【U盘-官方ISO直装】

Windows 10 官方系统安装/重装 制作启动盘的U盘微软官网下载Win10安装包创建启动盘U盘 安装Win10 本文采用U盘安装Windows10官方系统。 制作启动盘的U盘 微软官网下载Win10安装包 微软官网下载Win10安装包链接:https://www.microsoft.com/zh-cn/software-downloa…

[MySQL]MySQL数据库的介绍和库相关操作

目录 一、数据库介绍 1.什么是数据库 2.为什么使用数据库 3.数据库的操作运行逻辑 4.MySQL架构 5.SQL语句的分类 二、数据库的操作 1.数据库的连接 2.数据库的操作 创建数据库 查看数据库 显示数据库的创建语句 删除数据库 修改数据库 3.字符集和校验集 查看系…

亚博microros小车-原生ubuntu支持系列:13 激光雷达避障

一 背景知识 小车发了了数据包含激光雷达数据,类型是sensor_msgs/msg/LaserScan bohubohu-TM1701:~$ ros2 node info /YB_Car_Node /YB_Car_Node Subscribers: /beep: std_msgs/msg/UInt16 /cmd_vel: geometry_msgs/msg/Twist /servo_s1: std_msgs/…

机器学习 ---逻辑回归

逻辑回归是属于机器学习里面的监督学习,它是以回归的思想来解决分类问题的一种非常经典的二分类分类器。由于其训练后的参数有较强的可解释性,在诸多领域中,逻辑回归通常用作 baseline 模型,以方便后期更好的挖掘业务相关信息或提…

volatile之四类内存屏障指令 内存屏障 面试重点 底层源码

目录 volatile 两大特性 可见性 有序性 总结 什么是内存屏障 四个 CPU 指令 四大屏障 重排 重排的类型 为什么会有重排? 线程中的重排和可见性问题 如何防止重排引发的问题? 总结 happens-before 和 volatile 变量规则 内存屏障指令 写操作…

模拟电子技术-常用半导体器件

模拟电子技术-常用半导体器件 一、半导体基础知识二、PN结2.1 PN结简介2.2 PN结正向导电性2.2.1 正向电压2.2.2 反向电压2.2.3 PN结伏安特性 三、二极管3.1 二极管伏安特性曲线3.2 二极管参数和等效电路3.2.1 性能参数3.2.2 等效电路 3.3 二极管限幅和整流应用(正向特性)3.4 稳…

2024年博客之星主题创作|2024年蓝桥杯与数学建模年度总结与心得

引言 2024年,我在蓝桥杯编程竞赛和数学建模竞赛中投入了大量时间和精力,这两项活动不仅加深了我对算法、数据结构、数学建模方法的理解,还提升了我的解决实际问题的能力。从蓝桥杯的算法挑战到数学建模的复杂应用,我在这些竞赛中…

javascript-es6 (一)

作用域(scope) 规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问 局部作用域 函数作用域: 在函数内部声明的变量只能在函数内部被访问,外部无法直接访问 function getSum(){ //函数内部是函数作用…

使用eNSP配置GRE VPN实验

实验拓扑 实验需求 1.按照图示配置IP地址 2.在R1和R3上配置默认路由使公网区域互通 3.在R1和R3上配置GRE VPN,使两端私网能够互相访问,Tunne1口IP地址如图 4.在R1和R3上配置RIPv2来传递两端私网路由 GRE VPN配置方法: 发送端: …

Ansible自动化运维实战--script、unarchive和shell模块(6/8)

文章目录 一、script模块1.1、功能1.2、常用参数1.3、举例 二、unarchive模块2.1、功能2.2、常用参数2.3、举例 三、shell模块3.1、功能3.2、常用参数3.3、举例 一、script模块 1.1、功能 Ansible 的 script 模块允许你在远程主机上运行本地的脚本文件,其提供了一…

大数据Hadoop入门1

目录 相关资料 第一部分 1.课程内容大纲和学习目标 2.数据分析和企业数据分析方向 3.数据分析基本流程步骤 4.大数据时代 5.分布式和集群 6.Linux操作系统概述 7.VMware虚拟机概念与安装 8.centos操作系统的虚拟机导入 9.VMware虚拟机常规使用、快照 第二部分 1.课…

项目概述与规划 (I)

项目概述与规划 (I) JavaScript的学习已经接近尾声了,最后我们将通过一个项目来讲我们在JavaScript中学习到的所有都在这个项目中展现出来,这个项目的DEMO来自于Udemy中的课程,作者是Jonas Schmedtmann; 项目规划 项目步骤 用户…

项目集成RabbitMQ

文章目录 1.common-rabbitmq-starter1.创建common-rabbitmq-starter2.pom.xml3.自动配置1.RabbitMQAutoConfiguration.java2.spring.factories 2.测试使用1.创建common-rabbitmq-starter-demo2.目录结构3.pom.xml4.application.yml5.TestConfig.java 配置交换机和队列6.TestCon…

RK3568 adb使用

文章目录 一、adb介绍**ADB 主要功能****常用 ADB 命令****如何使用 ADB****总结** 二、Linux下载adb**方法 1:使用包管理器(适用于 Ubuntu/Debian 系统)****方法 2:通过 Snap 安装(适用于支持 Snap 的系统&#xff09…

STM32项目分享:智能宠物喂食系统(升级版)

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片: 哔哩哔哩视频链接: STM32智能宠物喂食系统(升级版) (资…

软件测试 —— 性能测试(jmeter)

软件测试 —— 性能测试(jmeter) 什么是jmeter安装jmeterjmeter常用组件线程组取样器结果树 我们之前学习了接口测试工具Postman,我们今天要学习的是性能测试工具——jmeter 什么是jmeter Apache JMeter 是一个开源的性能测试工具&#xff…

电阻补偿OTA的噪声分析

上文(补偿电阻对ota零极点的影响-CSDN博客)分析了补偿电阻对五管OTA零极点的影响,该篇借分析电阻补偿OTA的噪声来串联复习下噪声章节的一些基础概念。 1.噪声分析 辅助定理 开始分析OTA噪声之前,先引入一个辅助定理(R…

从CRUD到高级功能:EF Core在.NET Core中全面应用(四)

初识表达式树 表达式树:是一种可以描述代码结构的数据结构,它由一个节点组成,节点表示代码中的操作、方法调用或条件表达式等,它将代码中的表达式转换成一个树形结构,每个节点代表了代码中的操作例如,如果…