1 SoC中断 1.1 ARMv8中断 IPI:inter-processer interrupt 中断号0 - 15 PPI:per processor interrupts 中断号16 - 31 SPI:shared processor interrupts 中断号 32 - 224 SGI:software generated interrupts (SGI) 设备树是用来描述硬件信息的,因此里面不涉及软件中断SGI,在arm-gic.h文件中定义的只有SPI和PPI。 #define GIC_SPI 0 #define GIC_PPI 1
一般设备树中的中断都是SPI,那么interrupts = <0 208 1>;是什么意思呢? X:GIC_SPI或者GIC_PPI Y:物理中断号 - 32,SA8155 Z:触发方式 1 = low-to-high edge triggered 2 = high-to-low edge triggered (invalid for SPIs) 4 = active high level-sensitive 8 = active low level-sensitive (invalid for SPIs)
1.2 临界区开关CPU中断API arm:local_irq_disable() / local_irq_enable() 在ARM V6以上使用汇编指令CPSID / CPSIE(Current Program Status Interrupt Disable / Enable)用于快速的开关中断,早期版本使用汇编指令mrs和msr去更新cpsr。
x86:local_irq_disable调用汇编指令CLI(clear interrupt-enable flag,IF);local_irq_enable调用汇编指令STI(set interrupt-enable flag,IF)。
arm的cpsid和x86的CLI同时禁止了核间中断(IPI),CPU-x还会用IPI通知CPU-y进行resched,但是CPU-y可能已经禁用了中断而不会响应。
在中断中不能产生调度,在中断返回时才可能发生调度。事实上,早期的内核很大程度上是依赖local_irq_disable来做资源保护,这个看看2.4的内核源码就很清楚了,里面有大量的对local_irq_disable函数的直接调用。
1.3 Linux Kernel中断处理 request_threaded_irq() - 实时中断处理,比较好。
如果成功注册了一个中断(中断号为300,中断名字为oem),那么通过ps命令可以看到该线程 irq/300-oem
中断优化: echo 1 > /proc/sys/kernel/sched_boost
2 Linux内存管理 2.1 free命令 swapoff -a && swapon -a
free -h 显示的cache是指disk cache,也即是磁盘文件在内存中的缓存。 1) Clear PageCache only # sync; echo 1 > /proc/sys/vm/drop_caches
2) Clear dentries and inodes # sync; echo 2 > /proc/sys/vm/drop_caches
3) Clear PageCache, dentries and inodes # sync; echo 3 > /proc/sys/vm/drop_caches
2.2 内存页表 CONFIG_PTDUMP_CORE CONFIG_PTDUMP_DEBUGFS
/sys/kernel/debug/kernel_page_tables
page-types工具 tools/vm/page-types.c make -C tools/vm
2.3 栈空间 Linux查看修改线程默认栈空间大小(ulimit -s,单位KB),Linux默认是8MB。
2.3.1 kmalloc 用于kmalloc可分配的内存大小范围在32~131027(128k)字节,并且由于它用slab分配器来分配内存的,所以得到的内存大小可能比你申请的要大一些(它向上取2的N次幂整数)。而且如果开启了CONFIG_LARGE_ALLOCS选项,这个值可以更大,可以达到了32M。
2.3.2 malloc malloc申请的空间大于128KB的话,使用mmap系统调用在stack 和 heap中间的区域(共享内存映射区域)进行虚拟内存分配,其大小应该就是栈底与heap顶之间的空间最大值。
此时mmap()使用MAP_ANONYMOUS,并且不关心文件描述符fd的值;通过strace跟踪进程可以看到大量的带有MAP_ANONYMOUS的mmap()。
dlopen isn't a system call, it's a library function in the libdl library. Only system calls show up in strace. On Linux and on many other platforms (especially those that use the ELF format for executables), dlopen is implemented by opening the target library with open() and mapping it into memory with mmap(). mmap() is really the critical part here, it's what incorporates the library into the process' address space, so the CPU can execute its code. But you have to open() the file before you can mmap() it!
mmap vs read()/write()/lseek() https://blog.csdn.net/chenpuo/article/details/80658874
2.4 buddy and slab slab字面意思是被分割的厚板/石板,类似与buddy算法的含义(页可以按照2的次幂组织成一个元素,也可以分离,就像小伙伴一样,buddy算法因“时聚时散”这个表现而得名);slab的含义就是把大块的空间,分解为小块的空间。slab具体的特性是它包含不同的对象,就像书架一样,同一类型的对象就放在什么同一类型的slab(书架)里,因为一个slab可能装不下所有的对象,所以有些对象类型会有多个slab。slab并不是一开始就有的算法,它的出现是为了优化buddy算法,buddy算法以页(4096字节)为单位,进行管理,即使很小的数据修改,也会动用4096字节,花销大,而且数据这一块,那一块,不好管理。
所以,buddy系统就像一个大的书架,slab就像书架的格子一样。书架用于管理一个专业领域的书,如C语言/C++/JAVA/C#,而格子用于管理一个小类,C语言放在一个slab,C++放入一个slab....。而组成slab的“对象”就是具体的书本,如《C专家编程》,《C语言陷阱》等就是C语言这个slab 的对象。
Buddy APIs:alloc_pages()和__get_free_pages()等。
因为内存初始化的时间比分配和释放时间长好多,slab增加一个类似对象池的特性,slab会缓存已经被“释放”的对象,以便下次重用,不必再初始化。对象用该高速缓存结构kmem_cache描述。通过kmem_cache_create创建。虽然名为高速缓存,但是它不是硬件上的高速缓存,它只是主存上的区域,但是和硬件上的高速缓存高度相关。
2.5 ZONE_HIGHMEM 当内核空间大小是3GB – 4GB时,并不是所有的物理内存都是映射的,而是部分映射,需要时再动态将需要访问的物理内存映射到(3.896GB - 4GB)地址空间。使用CONFIG_HIGHMEM来配置。 vmalloc和kmalloc的区别: - vmalloc分配的一般为高端内存,只有当内存不够的时候才分配低端内存;kmalloc从低端内存分配 - vmalloc分配的物理地址一般不连续,而kmalloc分配的物理地址连续,两者分配的虚拟地址都是连续的 - vmalloc分配的一般为大块内存,而kmalloc一般分配的为小块内存(不超过128k)
2.6 64位CPU地址空间布局 查看物理和虚拟地址位数:/proc/cpuinfo 2.6.1 x86_64地址空间布局 - 64bit = 16MegaT - x86_64使用了40位物理地址线,48位虚拟地址空间 - 用户空间128T:0x0000,0000,0000,0000到0x0000,7fff,ffff,f000(最后12位不是fff,保留了一个页面) - 内核空间128T:0xffff,8000,0000,0000到0xffff,ffff,ffff,ffff;注意:该地址前4个都是f,这是因为目前实际上只用了64位地址中的48位(高16位是没有用的) - 从地址0x0000,7fff,ffff,ffff到0xffff,8000,0000,0000中间是一个巨大的空洞,是为以后的扩展预留的
2.6.2 ARM64地址空间布局 - ARM64使用了48位物理地址线,64位虚拟地址空间 - 用户空间128T:0x0000,0000,0000,0000到0x0000,7fff,ffff,ffff - 内核空间256T:0xffff,0000,0000,0000到0xffff,ffff,ffff,ffff
3 Linux scheduler 3.1 数据结构 #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)]
实时调度的结构体: struct rt_prio_array { ? ? DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */ ? ? struct list_head queue[MAX_RT_PRIO]; };
struct rt_rq { ? ? ? struct rt_prio_array ?active; ? ? ? [...] ? ? unsigned long rt_nr_running; ? ? ? ? // 可运行实时任务个数 ? ? ? unsigned long rt_nr_migratory; ? ? ? // 该运行队列上可以迁移到其他运行队列的实时任务个数 ? ? unsigned long rt_nr_uninterruptible; ? ? ? int highest_prio; ? ? ? int overloaded; ? }; ?
3.2 调度策略 linux的实时进程有两种调度策略,SCHED_FIFO和SCHED_RR(类似于打麻将,轮流坐庄),SCHED_FIFO是简单的队列调度,并且没有timeslice的限制,谁先来谁运行,除非是阻塞或者主动yield,否者将一直占用CPU,即使关中断也不能阻止优先级高的进程被调度运行。
实时进程从不激活到激活状态时,根据进程的优先级,找到对应的优先级列表头,然后插入到该优先级列表尾部。多个实时进程在SMP之间采用push和pull调度机制。
对于普通进程,是通过nice系统调用来调整优先级的。从内核角度讲[100,139]是普通进程的优先级的范围,100最高,139最低,默认是120。普通进程的优先级的作用和实时进程不同,普通进程优先级表示的是占用CPU的时间。深入linux内核架构中提到,普通优先级越高(100最高,139最低),享受的CPU time越多,相邻的两个优先级,高一级的进程比低一级的进程多占用10%的CPU,比如内核优先级数值为120的进程要比数值是121的进程多占用10%的CPU。
我们知道,linux的进程调度时机有: 1、进程状态转换的时刻:进程终止、进程睡眠 2、当前的进程的时间片用完(current->counter = 0) 3、设备驱动程序主动调用schedule 4、进程从中断、异常及系统调用返回用户态
struct sched_param { ? ? /* ... */ ? ? int sched_priority; ? ? /* ... */ };
int sched_setscheduler (pid_t pid, ? ? int policy, ? ? const struct sched_param *sp);
sched_setscheduler函数的第二个参数调度方法 : #define SCHED_NORMAL 0 #define SCHED_FIFO 1 #define SCHED_RR 2 #ifdef __USE_GNU # define SCHED_BATCH 3 #endif
SCHED_NORMAL(以前叫SCHED_OTHER)表示普通进程,对于普通进程,第三个参数sp->sched_priority只能是0 SCHED_FIFO 和SCHED_RR表示实时进程的调度策略,第三个参数的取值范围为[1,99]。 如果sched_setscheduler 优先级设置的值和调度策略不符合的话,会返回失败的。
3.3 CFS CFS:Completely Fair Scheduler,用于SCHED_NORMAL,kernel/sched_fair.c。对于SCHED_RR和SCHED_FIFO策略使用kernel/sched_rt.c
3.3.1 CFS大小核负载分配 @ /proc/sys/kernel/sched_downmigrate 这个值是个百分比,任务需求相对cpu能力的百分比。降低此值将会阻止任务迁移到小核上,对性能有利。
@ /proc/sys/kernel/sched_upmigrate 这个值是个百分比,任务需求相对cpu能力的百分比。提高这个值将会阻止任务往大核迁移,有利于功耗,不利于性能。
@ /proc/sys/kernel/sched_small_task @ /proc/sys/kernel/sched_mostly_idle_load @ /proc/sys/kernel/sched_mostly_idle_nr_run @ /proc/sys/kernel/sched_init_task_load @ /proc/sys/kernel/sched_prefer_idle @ /proc/sys/kernel/sched_migration_cost_ns
3.3.2 ARM big.LITTLE切换 代码路径: @ arch/arm/common/bL_switcher.c @ arch/arm/include/asm/bL_switcher.h @ drivers/cpufreq/arm_big_little.c
core_ctl模块 - 控制大核开关 @ /sys/devices/system/cpu/cpuX/core_ctl
3.4 进程抢占 在任何情况下使用spin_lock_irq都是安全的。因为它既禁止本地中断,又禁止内核抢占。 spin_lock比spin_lock_irq速度快,但是它并不是任何情况下都是安全的。
举个例子:进程A中调用了spin_lock(&lock)然后进入临界区,此时来了一个中断(interrupt),该中断也运行在和进程A相同的CPU上,并且在该中断处理程序中恰巧也会spin_lock(&lock)试图获取同一个锁。由于是在同一个CPU上被中断,进程A会被设置为TASK_INTERRUPT状态,中断处理程序无法获得锁,会不停的忙等,由于进程A被设置为中断状态,schedule()进程调度就无法再调度进程A运行,这样就导致了死锁!
但是如果该中断处理程序运行在不同的CPU上就不会触发死锁。 因为在不同的CPU上出现中断不会导致进程A的状态被设为TASK_INTERRUPT,只是换出。当中断处理程序忙等被换出后,进程A还是有机会获得CPU,执行并退出临界区。
所以在使用spin_lock时要明确知道该锁不会在中断处理程序中使用。
3.5 Linux ps命令返回参数解释 PPID:Parent Process ID VSIZE:Virtual Size,进程的虚拟内存大小 RSS:Resident Set Size,实际驻留“在内存中”的内存大小 WCHAN:Wait Channel(as an address),休眠进程在内核中的地址 PC:Program Counter,程序CPU指针
3.6 kworker是什么 显示格式:kworker/[u]%d:CPU_ID
u:是unbound的缩写,代表没有绑定特定的CPU,kworker/u8:0中的8是work_pool的ID。不带u的就是绑定特定cpu的workerq,它在init_workqueues中初始化,给每个cpu分配worker,如果该worker的nice小于0,说明它的优先级很高,所以就加了H(High)属性。通过ps可以看到内核创建的所有kworker。
譬如为CPU0创建的3个kworker:kworker/0:0、kworker/0:0H、kworker/u8:0
4 RTLinux 4.1 prio和rt_priority的区别 - 实时进程的优先级(rt_priority)数字越大则优先级越高,99最高,0最低;而普通进程正好相反,优先级(static_prio)数字越大则优先级越低,100最高,139最低(对应nice值-20 ~ 19) - 内核调度是按照task_struct中的prio来调度的,prio的值越小,优先级就越高。实时线程的rt_priority转换成prio:prio = MAX_RT_PRIO - 1 - p->rt_priority;普通线程的static_prio转换成prio:prio = static_prio = MAX_RT_PRIO + nice + 20 - 进程创建时的默认优先级是120,对应的nice值为0
4.2 priority inheritance in kernel/locking/rtmutex.c rt_mutex_adjust_prio() - 适用于优先级值小于100的实时任务
in kernel/sched/core.c rt_mutex_setprio()
4.3 中断线程化 in kernel/irq/manage.c setup_irq()
4.4 URLs https://wiki.linuxfoundation.org/realtime/start https://rt.wiki.kernel.org/index.php/Frequently_Asked_Questions
5 STM32中断 5.1 STM32中断编号 CMSIS IRQn = NVIC IRQn - 16 1)NVIC IRQn从1开始,所以NVIC中断1(Reset异常)对应CMSIS中断编号-15,NVIC中断16对应CMSIS中断编号0。 2)NVIC IRQn of SysTick等于15。 3)NVIC IRQn of PendSV等于14。
STM32的中断服务程序的名字不能自定义,必须使用官方已经定义好的名字,名字可参考如下的文件。 @ Drivers\CMSIS\Device\ST\STM32L0xx\Source\Templates\iar\startup_stm32l061xx.s 当然服务程序的具体内容还是自己写,放在stm32f10x_it.c里。
5.2 BASEPRI FreeRTOS中进入临界区时没有关闭所有中断,而是使用优先级屏蔽寄存器BASEPRI(= configMAX_SYSCALL_INTERRUPT_PRIORITY)关闭了部分中断;这个寄存器最多有9位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成0,则不关闭任何中断,0也是缺省值。
FreeRTOS任务代码中临界段的进入和退出主要是通过操作寄存器BASEPRI实现的。进入临界区BASEPRI关闭了所有大于等于宏定义configMAX_SYSCALL_INTERRUPT_PRIORITY所定义的中断优先级,这样临界段代码就不会被中断干扰到,而且实现任务切换功能的 PendSV 中断和SysTick滴答定时器中断是最低优先级中断,所以此任务在执行临界段代码期间是不会被其它高优先级任务打断的。退出临界段时重新操作BASEPRI寄存器,即打开被关闭的中断(这里我们不考虑不受FreeRTOS 管理的更高优先级中断)。
Cortex-M内核的“中断优先级寄存器”是以最高位(MSB)对齐的。STM32使用了优先级寄存器中的4位,则这4个位位于中断优先级寄存器的bit 4、bit5、bit6、bit7位。剩余的bit0 ~ bit3可以设置成任何值。所以FreeRTOS中的中断优先级计算是有移位操作的。
CMSIS以及不同的微控制器供应商提供了可以设置某个中断优先级的库函数。一些库函数的参数使用最低位对齐,另一些库函数的参数可能使用最高位对齐,所以,使用时应该查阅库函数的应用手册进行正确设置。
可以在FreeRTOSConfig.h中设置宏configMAX_SYSCALL_INTERRUPT_PRIORITY和configKERNEL_INTERRUPT_PRIORITY的值。(关于这两个宏可以参考参数设置一章,网址:http://openmcu.net/post/kernel-config.html)。这两个宏需要根据Cortex-M内核自身的情况进行设置,要以最高有效位对齐。比如某MCU使用中断优先级寄存器中的4位,设置configKERNEL_INTERRUPT_PRIORITY的值为5,则代码为: #define configKERNEL_INTERRUPT_PRIORITY (5<<(8-4))
对于每一个官方FreeRTOS演示例程,这也是在FreeRTOSConfig.h中要设置宏configKERNEL_INTERRUPT_PRIORITY为最低优先级时,为什么要将它设置为255(1111 1111B)的原因。使用这种方式指定这个值的原因是:FreeRTOS内核是直接在Cortex-M内核硬件上运行的(没有使用第三方接口库函数),要比大多数库函数先运行。现在也有开发第一个Cortex-M库函数计划。
5.3 IPR typedefstruct { ? ? vu32 ISER[2]; ? ? u32 RESERVED0[30]; ? ? vu32 ICER[2]; ? ? u32 RSERVED1[30]; ? ? vu32 ISPR[2]; ? ? u32 RSERVED2[30]; ? ? vu32 ICPR[2]; ? ? u32 RSERVED3[30]; ? ? vu32 IABR[2]; ? ? u32 RSERVED4[30]; ? ? vu32 IPR[15]; } NVIC_TypeDef;
NVIC IPR[15]:Interrupt Priority Registers,中断优先级控制寄存器组。STM32的中断分组与这个寄存器密切相关。因为STM32的中断多达60多个,所以STM32采用中断分组的办法来确定中断的优先级。IPR寄存器由15个32bit的寄存器组成,每个可屏蔽中断占8bit,这样总共可以表示15x4=60个可屏蔽中断。IPR[0]的[31:24],[23:16],[15:8],[7:0]分别对应中断3到0,总共对应60个外部中断。而每个可屏蔽中断占用的8bit并没有全部使用,只用了高4位。这4位又分为抢占优先级和子优先级。这两个优先级要根据SCB->AIRCR(System Control Block,Application Interrupt and Reset Register)中断分组的设置来决定。
简单介绍STM32的中断分组:STM32将中断分为0~4共5个组,该组是由SCB->AIRCR寄存器的bit10:8来定义的。具体优先级的确定和嵌套规则: (1)只能高抢先优先级的中断可以打断低抢占优先级的中断服务,构成中断嵌套; (2)当2个(N个)相同抢占优先级的中断出现,他们之间不能构成中断嵌套,但STM32首先响应子优先级高的中断; (3)当2个(N个)个抢占优先级和子优先级相同的中断出现,STM32首先响应中断通道所对应的中断向量地址低的中断,就是谁先发生谁先被执行。
5.4 SHPRx - System Handler Priority Registers SHPR1至SHPR3,3个32位寄存器,每8位设置一个中断优先级,共12个可配置的系统中断,8为里面用了高位configPRIO_BITS,其它位写无效,读为0。还有3个中断的优先级系统默认为-3、-2、-1。
5.5 示例代码 /* interrupt priority register */ static int command_dump_ipr(cli_node_t *cmd, int argc, char **argv) { ? ? const volatile uint8_t * const pcInterruptPriorityRegisters = ? ? ? ? (const volatile uint8_t * const)0xE000E3F0; ? ? uint8_t i;
? ??console_puts_lite(""CR_LF); ? ? console_puts_lite("configPRIO_BITS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= %d"CR_LF, ? ? ? ? ? ? configPRIO_BITS); ? ? console_puts_lite("configKERNEL_INTERRUPT_PRIORITY ? ? ? ? ? = 0x%02x"CR_LF, ? ? ? ? ? ? configKERNEL_INTERRUPT_PRIORITY); ? ? console_puts_lite("configMAX_SYSCALL_INTERRUPT_PRIORITY = 0x%02x"CR_LF, ? ? ? ? ? ? configMAX_SYSCALL_INTERRUPT_PRIORITY); ? ? console_puts_lite(""CR_LF);
? ??/* (4-7, 8-11, 12-15) */ ? ? console_puts_lite("System Handler Priority Registers"CR_LF); ? ? for (i = 0; i < 12; i++){ ? ? ? ? console_puts_lite("PRI_%d - 0x%02x"CR_LF, (4 + i), SCB->SHP[i]); ? ? } ? ? console_puts_lite(""CR_LF);
??? console_puts_lite("User Interrupt Priority Registers"CR_LF); ? ? for (i = 16; i < (16 + IRQ_NUMBER_MAX); i++) { ? ? ? ? console_puts_lite("IRQ%d - 0x%02x"CR_LF, ? ? ? ? ? ? ? ? (i - 16), pcInterruptPriorityRegisters[i]); ? ? } ? ? return 0; } DECLARE_CONSOLE_COMMAND(dump_ipr, command_dump_ipr, NULL);
5.6 中断延迟 性能相关的另外一个指标是中断延迟。这通常用从中断请求到中断服务程序第一条指令执行的时钟周期数来衡量。
6 FreeRTOS优先级反转 6.1 优先级反转 优先级反转是指一个低优先级的任务持有一个被高优先级任务所需要的共享资源。高优先任务由于因资源缺乏而处于受阻状态,一直等到低优先级任务释放资源为止。而低优先级获得的CPU时间少,如果此时有优先级处于两者之间的任务,并且不需要那个共享资源,则该中优先级的任务反而超过这两个任务而获得CPU时间。如果高优先级等待资源时不是阻塞等待,而是忙循环,则可能永远无法获得资源,因为此时低优先级进程无法与高优先级进程争夺CPU时间,从而无法执行,进而无法释放资源,造成的后果就是高优先级任务无法获得资源而继续推进。
6.2 解决方案 (1)设置优先级上限,给临界区一个高优先级,进入临界区的进程都将获得这个高优先级,如果其他试图进入临界区的进程的优先级都低于这个高优先级,那么优先级反转就不会发生。
eCos优先级上限(ceiling)例子: @ packages/kernel/v3_0/src/sync/mutex.cxx cyg_bool Cyg_Mutex::lock(void) { ? ? [...] }
void Cyg_Mutex::unlock(void) { ? ? [...] }
(2)优先级继承,当一个高优先级进程等待一个低优先级进程持有的资源时,低优先级进程将暂时获得高优先级进程的优先级别,在释放共享资源后,低优先级进程回到原来的优先级别。嵌入式系统FreeRTOS和VxWorks就是采用这种策略。
eCos优先级继承例子: @ packages/kernel/v3_0/src/sync/mutex.cxx cyg_bool Cyg_Mutex::lock(void) { ? ? [...] }
void Cyg_Mutex::unlock(void) { ? ? [...] }
FreeRTOS优先级继承例子: @ tasks.c vTaskPriorityInherit() - 需要mutex的高优先级Task,发现mutex被低优先级的Task持有。调整持有mutex的Task优先级等于当前等待mutex的Task优先级,这样持有mutex的低优先级Task获得了运行机会。 xTaskPriorityDisinherit() - 返回原来的优先级
(3)第三种方法就是使用中断禁止,通过禁止中断来保护临界区,采用此种策略的系统只有两种优先级:可抢占优先级和中断禁止优先级。前者为一般进程运行时的优先级,后者为运行于临界区的优先级。火星探路者正是由于在临界区中运行的气象任务被中断发生的通信任务所抢占才导致故障,如果有临界区的禁止中断保护,此一问题也不会发生。
7 Abbreviations ARM CM4 BASEPRI:优先级屏蔽寄存器最多有9位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成0,则不关闭任何中断,0也是缺省值。FreeRTOS进入临界区时BASEPRI的值等于configMAX_SYSCALL_INTERRUPT_PRIORITY BFS:Brain Fuck Scheduler,又称脑残调度器 CM4 R13:for MSP & PSP,the tasks are using the PSP(Process Stack Pointer), while the interrupts are using the MSP(Main Stack Pointer) CMSIS:Cortex-Microcontroller Software Interface Standard NVIC:Nested Vectors Interrupts Controller NVIC IPR:Interrupt Priority Registers PendSV:Pendable 服务是一个中断请求,如果没有其他中断需要响应时,系统将强制执行上下文切换 pi_waiters:priority inheritance,优先级继承 SVCall:SuperVisor Call由SVC指令触发,FreeRTOS用它来启动任务调度 SCHED_RR:Round-Robin,轮流调度算法(实时调度策略) SHPRx:CM4 System Handler Priority Registers STM32 AIRC:Application Interrupt and Reset Register TIF_NEED_RESCHED:Thread Info Flag Bionic brk():break(堆顶端称作program break) intercepting:拦截系统调用 ptrace:process trace pt_regs:ptrace registers(对应命令PTRACE_GETREGS) strace:system call trace
|