Linux arm64异常简介和系统调用过程

文章目录

  • 一、异常简介
    • 1.1 Exception levels
    • 1.2 异常类型
  • 二、系统调用简介
    • 2.1 SVC指令
    • 2.2 VBAR
    • 2.3 系统调用保存现场
    • 2.4 系统调用返回
  • 三、Linux 内核分析
  • 参考资料

一、异常简介

在ARM64体系架构中,异常是处理器在执行指令时可能遇到的不寻常情况或事件。这些异常可以是由软件或硬件引发的。ARM64体系架构定义了一套异常模型,用于处理和响应这些异常情况。

1.1 Exception levels

Armv8-A体系结构定义了一组异常级别,EL0到EL3,其中:

● 如果ELn是异常级别,则n的值增加表示软件执行权限增加。
● 在EL0执行称为无特权执行。EL0为非特权模块,应用层。
● 在EL1执行称为特权特权执行。EL1为特权模块,操作系统内核层。
● EL2提供对虚拟化的支持。
● EL3支持在两种安全状态(安全状态和非安全状态)之间切换。

EL0 Applications.
EL1 OS kernel and associated functions that are typically described as privileged.
EL2 Hypervisor.
EL3 Secure monitor.

一个armv8系统实现可能不包括所有的Exception级别。所有实现都必须包括EL0和EL1。EL2和EL3是可选的。

从上面可看到armv8最大支持EL0~EL3四个exception level,EL0的execution privilege最低,EL3的execution privilege最高。当发生异常的时候,系统的exception会迁移到更高的exception level或者维持不变,但是绝不会降低。此外,不会有任何的异常会去到EL0。

1.2 异常类型

在Linux ARM64架构中,同步异常和异步异常与处理器的异常处理机制和中断控制器有关。

(1)同步异常(Synchronous Exceptions):
在ARM64架构中,同步异常与当前指令的执行直接相关,它们在指令执行期间同步地引发。常见的同步异常包括:

●未定义指令异常:当尝试执行在ARM64架构中未定义的指令时,会引发该异常。包括在不适当的异常级别执行指令、禁用的指令、以及未被分配的指令位模式。

●非法执行状态异常:当PSTATE.IL(非法执行状态)设置为1时,尝试执行指令会引发该异常。

●堆栈指针(SP)未对齐异常:当堆栈指针未按照对齐要求进行对齐时,会触发该异常。

●程序计数器(PC)未对齐异常:当尝试执行具有错误对齐的指令时,会引发该异常。

●引发异常的指令:特定指令(如SVC、HVC或SMC)可能触发异常。

●被捕获指令异常:当尝试执行被定义为在较高异常级别被捕获的指令时,会引发该异常。

●内存相关异常:由内存地址转换系统引发的异常,包括与指令执行或内存访问相关的指令异常和数据异常。

●数据地址未对齐异常:当尝试使用错误对齐的地址访问内存时,会触发该异常。

●调试异常:与调试相关的各种异常,例如断点指令异常、断点异常、观测点异常、向量捕获异常和软件单步异常。

●被捕获的浮点异常(如果支持):在支持浮点异常捕获的实现中,当发生被捕获的IEEE浮点异常时,会引发该异常。

对于同步异常,Linux内核会根据异常类型执行相应的异常处理程序,例如调用适当的异常处理函数、进行错误处理或发送信号给相关进程。

(2)异步异常(Asynchronous Exceptions):
在ARM64架构中,异步异常是与当前指令执行无直接关联的异常,它们以异步的方式引发。常见的异步异常包括:

在Armv8-A架构中,被带入AArch64状态的异步异常也被称为中断。中断分为两种类型:
物理中断(Physical interrupts):这些是从处理器外部发送给处理器的信号。它们包括:

SError:系统错误中断。
IRQ:普通中断请求。
FIQ:快速中断请求。

虚拟中断(Virtual interrupts):软件在EL2执行时可以启用和挂起的中断。虚拟中断从EL0或EL1传递到EL1。
虚拟中断的名称与物理中断对应:

vSError:虚拟系统错误中断。
vIRQ:虚拟普通中断请求。
vFIQ:虚拟快速中断请求。

对于异步异常,ARM64架构中的处理方式通常是由中断控制器来管理和处理。中断控制器会根据中断优先级和配置,将异步事件传递给处理器,并触发相应的中断处理程序。

二、系统调用简介

2.1 SVC指令

系统调用属于异常的同步软件异常。

系统调用是通过执行SVC、HVC或SMC指令触发的,这里我们指讨论SVC指令:
默认情况下,执行SVC指令会生成一个Supervisor Call,这是一个针对EL1的同步异常。这为在EL0执行的软件提供了一种调用在EL1执行的操作系统或其他软件的机制。

在ARM64体系架构中EL0是用户空间,EL1是内核空间。

SVC指令提供了在不同执行级别(EL)之间进行通信和交互的机制。通过执行SVC指令,EL0中的用户空间程序可以请求EL1中运行的操作系统或其他软件执行特权操作。

SVC Generate exception targeting Exception level 1
Supervisor Call causes an exception to be taken to EL1.

2.2 VBAR

当处理器处于使用AArch64执行状态时,当处理器执行到一个异常级别(Exception level)引发异常时,执行将被强制转移到异常向量(exception vector)所指示的地址上。异常向量表(vector table)位于该异常级别的内存中,占据一系列以字对齐的地址。

在ARMv8-A体系结构中,每个异常级别都有一个关联的向量基地址寄存器(Vector Base Address Register,VBAR),它定义了该异常级别对应的异常基地址。向量基地址决定了异常向量表在特定异常级别下的起始地址。当异常发生时,处理器使用与当前异常级别相关联的VBAR寄存器来查找相应的向量表,并跳转到该表中对应的异常向量。

通过为每个异常级别使用独立的向量表和VBAR寄存器,ARMv8-A体系结构在不同特权级别下的异常处理中提供了灵活性和定制性。该机制能够高效处理异常和中断,确保在不同情况下的适当处理和恢复。

处理器在用户空间EL0执行系统调用时,即执行svc指令,发生了异常,处理器跳转和执行相关的异常处理指令。异常相关的处理指令存储在一个表中,即异常向量表。对于ARM64体系架构,EL1对应一个异常向量表,其地址存放在向量基址寄存器(VBAR_EL1, Vector Base Address Register )中。

对于AArch64状态的异常,the vector table提供以下信息:
以下是关于异常的一些信息
(1)异常类型:

— Synchronous exception.
— SError.
— IRQ.
— FIQ

(2)异常级别和相关信息:
异常发生的异常级别:指示异常发生的特权级别,例如EL0(用户级别)、EL1(操作系统级别)等。
正在使用的堆栈指针:用于跟踪异常处理期间的堆栈操作。
寄存器文件的状态:指示异常发生时寄存器文件中各个寄存器的值和状态。
在这里插入图片描述
说明:
(1)这个表有四个异常条目,每个异常条目有四种异常类型:同步异常(Synchronous exception),IRQ,FIQ和SError。
(2)每一个异常入口占用0x80 bytes空间,每一个异常入口可以放置多32条指令。ARMv8指令集支持64位指令集,但每一条指令的位宽是32位,而不是64位。

0x80(128) / 4 = 32 

四个异常条目:
(1)如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL0,对应着第一个异常条目。
(2)如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL1/2/3,对应着第二个异常条目。
(3)如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH64模式,对应着第三个异常条目。
(4)如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH32模式,对应着第四个异常条目。

对于AARCH64模式异常指令svc,处理器会导致exception level切换,异常等级从EL0切换到EL1,对应着第三个异常条目:如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH64模式,那么使用第三个异常条目。

Lower Exception level, where the implemented level immediately lower than the target level is using AArch64.b

对于异常指令svc属于同步异常(Synchronous exception),因此svc异常处理器会跳转到 VBAR_EL1 + 0x400 地址处的异常向量中。

2.3 系统调用保存现场

当系统调用从用户态到内核态的时候,首先要做的第一件事情,就是将用户态运行过程中的 CPU 上下文保存起来,其实主要就是保存在这个结构的寄存器变量里。这样当从内核系统调用返回的时候,才能让进程在刚才的地方接着运行下去。

应用层程序执行svc系统调用指令时,会将用户态此时所有通用寄存器的状态保存起来,以便从系统调用返回时恢复状态。将进程用户态此时所有通用寄存器的状态保存在该进程的内核栈中的pt_regs栈框中。

在内核栈的最高地址端,存放的是另一个结构 pt_regs,这个结构体保存着进程从应用层进入到内核层时,用户态寄存器的状态。
struct pt_regs结构体:

/** This struct defines the way the registers are stored on the stack during an* exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for* stack alignment). struct user_pt_regs must form a prefix of struct pt_regs.*/
struct pt_regs {union {struct user_pt_regs user_regs;struct {u64 regs[31];u64 sp;u64 pc;u64 pstate;};};u64 orig_x0;
#ifdef __AARCH64EB__u32 unused2;s32 syscallno;
#elses32 syscallno;u32 unused2;
#endifu64 orig_addr_limit;/* Only valid when ARM64_HAS_IRQ_PRIO_MASKING is enabled. */u64 pmr_save;u64 stackframe[2];
};

如下图所示:
在这里插入图片描述
关于进程内核栈请参考:Linux 进程管理之内核栈和struct pt_regs

2.4 系统调用返回

当操作系统的异常处理(这里只描述svc异常)完成后,执行一条ERET指令就可以从异常返回。寄存器ELR_ELx存放svc指令异常返回的地址,发生系统调用svc指令时,系统肯定是在用户空间的地址,将svc指令的下一条指令的地址保存在寄存器ELR_ELx中,当系统调用返回时,即执行ERET指令时,返回svc异常指令现场,从寄存器ELR_ELx取出svc指令的下一条指令的地址,执行该指令。执行ERET指令时会从寄存器ELR_ELx恢复PC指针。

三、Linux 内核分析

(1)汇编入口:

// linux-5.4.18/arch/arm64/kernel/entry.S/** Exception vectors.*/.pushsection ".entry.text", "ax".align	11
ENTRY(vectors)kernel_ventry	1, sync_invalid			// Synchronous EL1tkernel_ventry	1, irq_invalid			// IRQ EL1tkernel_ventry	1, fiq_invalid			// FIQ EL1tkernel_ventry	1, error_invalid		// Error EL1tkernel_ventry	1, sync				// Synchronous EL1hkernel_ventry	1, irq				// IRQ EL1hkernel_ventry	1, fiq_invalid			// FIQ EL1hkernel_ventry	1, error			// Error EL1hkernel_ventry	0, sync				// Synchronous 64-bit EL0kernel_ventry	0, irq				// IRQ 64-bit EL0kernel_ventry	0, fiq_invalid			// FIQ 64-bit EL0kernel_ventry	0, error			// Error 64-bit EL0#ifdef CONFIG_COMPATkernel_ventry	0, sync_compat, 32		// Synchronous 32-bit EL0kernel_ventry	0, irq_compat, 32		// IRQ 32-bit EL0kernel_ventry	0, fiq_invalid_compat, 32	// FIQ 32-bit EL0kernel_ventry	0, error_compat, 32		// Error 32-bit EL0
#elsekernel_ventry	0, sync_invalid, 32		// Synchronous 32-bit EL0kernel_ventry	0, irq_invalid, 32		// IRQ 32-bit EL0kernel_ventry	0, fiq_invalid, 32		// FIQ 32-bit EL0kernel_ventry	0, error_invalid, 32		// Error 32-bit EL0
#endif
END(vectors)

Linux 内核使用vectors作为异常向量表,刚好和arm官方手册Vector Base Address Register (VBAR)的相对应。

前面说到对于同步异常指令svc,处理器会跳转到 VBAR_EL1 + 0x400 地址处的异常向量中。
VBAR_EL1 存放的是vectors的基地址。

一个表项128字节,十六进制即 0x80。

偏移异常描述
Current Exception level with SP_EL0
0x00kernel_ventry 1, sync_invalid // Synchronous EL1t
0x80kernel_ventry 1, irq_invalid // IRQ EL1t
0x100kernel_ventry 1, fiq_invalid // FIQ EL1t
0x180kernel_ventry 1, error_invalid // Error EL1t
Current Exception level with SP_ELx, x>0
0x200kernel_ventry 1, sync // Synchronous EL1h
0x280kernel_ventry 1, irq // IRQ EL1h
0x300kernel_ventry 1, fiq_invalid // FIQ EL1h
0x380kernel_ventry 1, error // Error EL1h
Lower Exception level, where the implemented level immediately lower than the target level is using AArch64
0x400kernel_ventry 0, sync // Synchronous 64-bit EL0
0x480kernel_ventry 0, irq // IRQ 64-bit EL0
0x500kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0
0x580kernel_ventry 0, error // Error 64-bit EL0
Lower Exception level, where the implemented level immediately lower than the target level is using AArch32
0x600kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0
0x680kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0
0x700kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0
0x780kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0

vectors的基地址 + 0x400 =

kernel_ventry	0, sync				// Synchronous 64-bit EL0
// linux-5.4.18/arch/arm64/kernel/entry.S/** EL0 mode handlers.*/.align	6
el0_sync:kernel_entry 0mrs	x25, esr_el1			// read the syndrome registerlsr	x24, x25, #ESR_ELx_EC_SHIFT	// exception classcmp	x24, #ESR_ELx_EC_SVC64		// SVC in 64-bit stateb.eq	el0_svccmp	x24, #ESR_ELx_EC_DABT_LOW	// data abort in EL0b.eq	el0_dacmp	x24, #ESR_ELx_EC_IABT_LOW	// instruction abort in EL0b.eq	el0_ia......

在el0_sync汇编函数中,首先通过kernel_entry保存异常现场。然后从esr_el1寄存器中读取异常类型(EC),当异常类型为ESR_ELx_EC_SVC64是,跳转到 el0_svc 汇编函数。

// linux-5.4.18/arch/arm64/kernel/entry.S/** SVC handler.*/.align	6
el0_svc:gic_prio_kentry_setup tmp=x1mov	x0, spbl	el0_svc_handlerb	ret_to_user
ENDPROC(el0_svc)

el0_svc 汇编函数跳转到 el0_svc_handler 函数。

(2)C语言入口

// linux-5.4.18/arch/arm64/kernel/syscall.casmlinkage void el0_svc_handler(struct pt_regs *regs)
{el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
}
// linux-5.4.18/arch/arm64/include/asm/ptrace.h/** This struct defines the way the registers are stored on the stack during an* exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for* stack alignment). struct user_pt_regs must form a prefix of struct pt_regs.*/
struct pt_regs {union {struct user_pt_regs user_regs;struct {u64 regs[31];u64 sp;u64 pc;u64 pstate;};};u64 orig_x0;......
};
// linux-5.4.18/include/uapi/asm-generic/unistd.h#define __NR_syscalls 436
// linux-5.4.18/arch/arm64/include/asm/syscall.htypedef long (*syscall_fn_t)(const struct pt_regs *regs);// linux-5.4.18/arch/arm64/kernel/sys.cconst syscall_fn_t sys_call_table[__NR_syscalls] = {[0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall,
#include <asm/unistd.h>
};
static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,const syscall_fn_t syscall_table[])
{regs->orig_x0 = regs->regs[0];regs->syscallno = scno;invoke_syscall(regs, scno, sc_nr, syscall_table);}
static void invoke_syscall(struct pt_regs *regs, unsigned int scno,unsigned int sc_nr,const syscall_fn_t syscall_table[])
{long ret;if (scno < sc_nr) {syscall_fn_t syscall_fn;syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];ret = __invoke_syscall(regs, syscall_fn);}regs->regs[0] = ret;
}
static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
{return syscall_fn(regs);
}

(3)流程简介

el0 svc-->el1 vectors-->kernel_ventry	0, sync				// Synchronous 64-bit EL0-->el0_sync-->el0_svc-->el0_svc_handler-->el0_svc_common-->invoke_syscall-->__invoke_syscall-->syscall_fn(regs)

从系统调用表中sys_call_table根据系统调用号取出对应的系统调用回调函数,然后去执行对应的系统调用回调函数。

参考资料

Linux 5.4.18
armv8手册

https://blog.csdn.net/luteresa/article/details/120263414
https://zhuanlan.zhihu.com/p/578252899
http://www.wowotech.net/238.html

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

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

相关文章

链表经典OJ题(链表回文结构,链表带环,链表的深拷贝)

目录 前言 1.反转一个单链表。 2. 给定一个带有头结点 head 的非空单链表&#xff0c;返回链表的中间结点。 3.链表的回文结构。 4.链表带环问题&#xff08;*****&#xff09; 4.1是否带环 4.2 入环的节点 5.随机链表的复制&#xff08;链表的深拷贝&#xff09; 前言…

Redis的三种特殊数据类型

文章目录 一、Redis geospatial 地理位置二、Redis Hyperloglog 基数统计的算法三、Redis Bitmaps 位存储&#xff08;0、1&#xff09;总结 一、Redis geospatial 地理位置 1.geoadd&#xff1a;将指定的地理空间位置&#xff08;纬度、经度、名称&#xff09;添加到指定的ke…

人工智能-卷积神经网络(LeNet)

为了能够应用softmax回归和多层感知机&#xff0c;我们首先将每个大小为\(28\times28\)的图像展平为一个784维的固定长度的一维向量&#xff0c;然后用全连接层对其进行处理。 而现在&#xff0c;我们已经掌握了卷积层的处理方法&#xff0c;我们可以在图像中保留空间结构。 同…

Dubbo从入门到上天系列第五篇:Dubbo3与JDK17不兼容问题展示

文章目录 一&#xff1a;JDK 与 Dubbo版本对应问题说明 1&#xff1a;问题1 2&#xff1a;问题2 二&#xff1a;Spring与JDK版本对应关系 1&#xff1a;对应关系详图 2&#xff1a;JDK与Major对应关系图 大神链接&#xff1a;作者有幸结识技术大神孙哥为好友&#xff0c…

[ Linux Busybox ] nandwrite 命令解析

文章目录 相关结构体nandwrite 函数实现nandwrite 实现流程图 文件路径&#xff1a;busybox-1.20.2/miscutils/nandwrite.c 相关结构体 MTD 相关信息结构体 struct mtd_info_user {__u8 type; // MTD 设备类型__u32 flags; // MTD设备属性标志__u32…

基于STM32控制直流电机加减速正反转仿真设计

**单片机设计介绍&#xff0c;基于STM32控制直流电机加减速正反转仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 本设计由STM32F103、L298N电机驱动电路、按键电路组成。通过按键可以控制电机&#xff0c;正转、反转、加…

商越科技:渗透测试保障平台安全,推动线上采购高效运转

商越科技是数字化采购解决方案提供商&#xff0c;在同赛道企业中始终保持前列。商越科技通过自主研发的智能采购中台、SaaS应用及运营服务等为企业搭建专属的互联网采购平台&#xff0c;帮助企业实现采购数字化以及智能化转型&#xff0c;提高工作效率、降低采购成本。 打造数字…

Linux基础开发工具之调试器gdb

文章目录 1.编译成的可调试的debug版本1.1gcc test.c -o testdebug -g1.2readelf -S testdebug | grep -i debug 2.调试指令2.0quit退出2.1list/l/l 数字: 显示代码2.2run/r运行2.3断点相关1. break num/b num: 设置2. info b: 查看3. d index: 删除4. n: F10逐过程5. p 变量名…

Java必刷入门递归题×5(内附详细递归解析图)

目录 1.求N的阶乘 2.求12...N的和 3.顺序打印数字的每一位 4.求数字的每一位之和 5.求斐波拉契数列 1.求N的阶乘 &#xff08;1&#xff09;解析题目意思 比如求5的阶乘&#xff0c;符号表示就是5&#xff01;&#xff1b;所以5&#xff01;5*4*3*2*1我们下面使用简单的…

SSM图书管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 图书管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和 数据库&#xff0c;系统主要…

Linux-Docker的基础命令和部署code-server

1.安装docker 1.安装需要的安装包 yum install -y yum-utils2.设置镜像仓库 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3.安装docker yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin do…

多彩的树 -----题解(状压dp + 容斥原理)

目录 多彩的树 题目描述 输入描述: 输出描述: 输入 输出 思路解析&#xff1a; 代码实现&#xff1a; 多彩的树 时间限制&#xff1a;C/C 5秒&#xff0c;其他语言10秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld 题目描述 …

【Springboot】Vue3-Springboot引入JWT实现登录校验以及常见的错误解决方案

文章目录 前言一、JWT简单介绍二、token校验设计思路三、使用步骤Springboot部署JWT引入依赖&#xff1a;创建登录实体类后端&#xff1a;LoginController.java路由守卫函数 四、问题 前言 项目版本&#xff1a; 后端&#xff1a; Springboot 2.7、 Mybatis-plus、Maven 3.8.1…

C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发004:游戏核心消息处理 - 玩家类的实现

文章目录 0 代码仓库1 需求2 AOI设计2.1 AOI算法简介2.2 AOI数据结构及实现2.2.1 玩家2.2.2 网格对象2.2.3 游戏世界矩形2.2.4 获取周围玩家的实现2.2.5 代码测试 2.3 GameRole结合AOI创建玩家2.3.1 创建游戏世界全局对象-GameRole继承AOIWorld的Player2.3.2 把玩家到游戏世界的…

1.docker linux离线环境安装 20.1.0.12

目录 概述下载解压docker 卸载docker 安装检查安装环境常用命令结束 概述 docker离线环境安装 20.1.0.12 , centos 7.x 下载 安装包下载 解压 [roothadoop01 soft]# unzip docker_20_1_0_12.zip [roothadoop01 soft]# cd docker_20_1_0_12 [roothadoop01 docker_20_1_0_1…

数据结构:树的基本概念(二叉树,定义性质,存储结构)

目录 1.树1.基本概念1.空树2.非空树 2.基本术语1.结点之间的关系描述2.结点、树的属性描述3.有序树、无序树4.森林 3.树的常考性质 2.二叉树1.基本概念2.特殊二叉树1.满二叉树2.完全二叉树3.二叉排序树4.平衡二叉树 3.常考性质4.二叉树的存储结构1.顺序存储2.链式存储 1.树 1.…

亚马逊云AI应用科技创新下的Amazon SageMaker使用教程

目录 Amazon SageMaker简介 Amazon SageMaker在控制台的使用 模型的各项参数 pytorch训练绘图部分代码 Amazon SageMaker简介 亚马逊SageMaker是一种完全托管的机器学习服务。借助 SageMaker&#xff0c;数据科学家和开发人员可以快速、轻松地构建和训练机器学习模型&#…

ARM寄存器及功能介绍/R0-R15寄存器

1、ARM 寄存器组介绍 ARM 处理器一般共有 37 个寄存器&#xff0c;其中包括&#xff1a; &#xff08;1&#xff09; 31 个通用寄存器&#xff0c;包括 PC&#xff08;程序计数器&#xff09;在内&#xff0c;都是 32 位的寄存器。 &#xff08;2&#xff09; 6 个状态寄存器…

服务号如何升级订阅号

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;首先我们要知道服务号和订阅号有什么区别。服务号侧重于对用户进行服务&#xff0c;每月可推送4次&#xff0c;每次最多8篇文章&#xff0c;发送的消息直接显示在好友列表中。订阅号更侧重于信息传…

通信信道:无线信道中衰落的类型和分类

通信信道&#xff1a;无线信道中衰落的类型和分类 在进行通信系统仿真时&#xff0c;简单的情况下选择AWGN信道&#xff0c;但是AWGN信道和真是通信中的信道相差甚远&#xff0c;所以需要仿真各种其他类型的信道&#xff0c;为了更清楚理解仿真信道的特点&#xff0c;首先回顾…