bootlog analysis

printenv

‘’’
arch=arm
baudrate=115200
board=s32-gen1
board_name=s32-gen1
boot_fdt=try
boot_mtd=booti
bootargs=root=/dev/ram rw earlycon loglevel=7
bootcmd=mmc dev ${mmcdev}; if mmc rescan; then if run loadimage; then run mmcboot; else run netboot; fi; else run netboot; fi
bootdelay=2
bootscript=echo Running bootscript from mmc …; source
console=ttyLF0
cpu=armv8
fdt_addr=0x83E00000
fdt_enable_hs400es=fdt addr ${fdt_addr}; fdt rm /usdhc no-1-8-v; fdt resize;
fdt_file=fsl-s32r45-evb.dtb
fdt_high=0xa0000000
fdt_override=;
fdtcontroladdr=ffa99000
flashboot=echo Booting from flash…; run flashbootargs;sf probe 6:0;sf read ${loadaddr} ${kernel_flashaddr} ${kernel_maxsize};sf read ${fdt_addr} ${fdt_flashaddr} ${fdt_maxsize};sf read ${ramdisk_addr} ${ramdisk_flashaddr} ${ramdisk_maxsize};${boot_mtd} ${loadaddr} ${ramdisk_addr} ${fdt_addr};
flashbootargs=setenv bootargs console=${console},${baudrate} root=/dev/ram rw earlycon ;setexpr fip_flashaddr 0x0;setexpr kernel_flashaddr (0x0 + 0x1f0000);setenv kernel_maxsize 0x1400000;setexpr fdt_flashaddr (0x0 + 0x15f0000);setenv fdt_maxsize 0x100000;setexpr ramdisk_flashaddr (0x0 + 0x16f0000);setenv ramdisk_maxsize 0x2000000;
gatewayip=192.168.30.1
hwconfig=pcie0:mode=rc,clock=int;pcie1:mode=sgmii,clock=ext,fmhz=125,xpcs_mode=2G5
image=Image
initrd_high=0xFE1FFFFF
ipaddr=192.168.30.60
jtagboot=echo Booting using jtag…; ${boot_mtd} ${loadaddr} ${ramdisk_addr} ${fdt_addr}
jtagsdboot=echo Booting loading Linux with ramdisk from SD…; run loadimage; run loadramdisk; run loadfdt;${boot_mtd} ${loadaddr} ${ramdisk_addr} ${fdt_addr}
loadaddr=0x80000000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}; run fdt_override;
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
loadramdisk=fatload mmc ${mmcdev}:${mmcpart} ${ramdisk_addr} ${ramdisk}
loadtftpfdt=tftp ${fdt_addr} ${fdt_file};
loadtftpimage=tftp ${loadaddr} ${image};
loadtftpramdisk=tftp ${ramdisk_addr} ${ramdisk};
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot} earlycon
mmcboot=echo Booting from mmc …; run mmcargs; if run loadfdt; then ${boot_mtd} ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi;
mmcdev=0
mmcpart=1
mmcroot=/dev/mmcblk0p2 rootwait rw
netargs=setenv bootargs console=${console},${baudrate} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp earlycon
netboot=echo Booting from net …; run netargs; if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${image}; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if ${get_cmd} ${fdt_addr} ${fdt_file}; then ${boot_mtd} ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then ${boot_mtd}; else echo WARN: Cannot load the DT; fi; fi; else ${boot_mtd}; fi;
netmask=255.255.255.0
nfsboot=echo Booting from net using tftp and nfs…; run nfsbootargs;run loadtftpimage; run loadtftpfdt;${boot_mtd} ${loadaddr} - ${fdt_addr};
nfsbootargs=setenv bootargs console=${console},${baudrate} root=/dev/nfs rw ip=${ipaddr}:${serverip}::${netmask}::eth0:off nfsroot=${serverip}:/tftpboot/rfs,nolock,v3,tcp earlycon
ramdisk=rootfs.uimg
ramdisk_addr=0x84000000
s32cc_gmac1_mode=enable
s32cc_gmac_mode=enable
script=boot.scr
serverip=10.0.0.1
soc=s32
stderr=serial@401C8000
stdin=serial@401C8000
stdout=serial@401C8000
update_sd_firmware=if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; if mmc dev ${mmcdev}; then if ${get_cmd} ${update_sd_firmware_filename}; then setexpr fw_sz ${filesize} / 0x200; setexpr fw_sz ${fw_sz} - 7; setexpr loadaddr ${loadaddr} + 0x1000; mmc write ${loadaddr} 0x8 ${fw_sz}; fi; fi
update_sd_firmware_filename=fip.s32
vendor=freescale

Environment size: 3756/8188 bytes

‘’’

ToolsMethods

首行空两格
首行空两格
首行空两格
首行空两格
首行空两格
首行空两格
首行空两格
首行空两格

首行空两格

首行空两格

字体颜色

字体大小

字体大小

==字体高亮==
字体高亮




明月几时有,
把酒问青天。
不知天上宫阙,
今夕是何年。

文字居中显示

脚注一^footNote1
脚注二^footNote2

  1. 第一项
  2. 第二项
  3. 第三项
  • 第一项
  • 第二项
  • 第一项
  • 第二项
  • 第一项
  • 第二项
  1. 第一项
    • 第一个元素
    • 第二个元素
  2. 第二项
    • 第一个元素
    • 第二个元素

一级引用

二级引用

fun()函数

1
2
3
4
int main()
{
std::cout << "Hello Markdown";
}

链接名称 // CSDN主页
<链接地址> // https://www.csdn.net


2.10 表格
  Markdown制作表格使用|来分隔不同的单元格,使用-来分隔表头和其他行。
对齐方式:

:—- 设置内容和标题栏左对齐
:—: 设置内容和标题栏居中对齐
—-: 设置内容和标题栏右对齐

语法格式:

11 22
22 22
表 头 1 表 头 2 表头3
居中对齐 左对齐 右对齐

跳转到:测试
| -
| –
| —
| —-
| —–
| ——
测试

文本^上标^
文本下标

  • 计划任务
  • 已完成任务

Linux System command description

Process

常用命令总结

1.ps -eLo pid,tid,%cpu,%mem,psr,comm
2.cpu load 1S 打印一次: mpstat -P ALL 1
3.nice -n -20 ./xxx.elf
4.git diff > xxx.patch
5.git diff --name-only
    git diff HEAD file1 > file1.patch  file1文件包含所在的路径
    git diff HEAD file2 > file2.patch

ps

`ps`命令提供了许多选项和格式化输出标志,以满足不同需求。以下是一些常用的`ps`选项和格式化输出标志:

1. **常用`ps`选项**:
- `-e`: 显示系统中所有进程。
- `-f`: 显示详细的进程信息,包括父进程、终端、CPU使用率等。
- `-l`: 显示更详细的进程信息,包括进程状态、优先级、虚拟内存大小等。
- `-aux`: 显示所有进程的详细信息,包括用户、CPU使用率等。
- `-A`: 显示所有进程,包括守护进程(daemon)。
- `-t`: 显示与指定终端关联的进程。

1. **格式化输出标志**:
- `pid`: 进程ID。
- `ppid`: 父进程ID。
- `uid`: 用户ID。
- `gid`: 用户组ID。
- `tty`: 终端。
- `ni`: 进程的nice值。
- `sz`: 进程使用的虚拟内存大小。
- `vsz`: 进程使用的虚拟内存大小(以K为单位)。
- `rss`: 进程使用的物理内存大小。
- `%cpu`: CPU利用率。
- `%mem`: 内存利用率。
- `comm`: 进程名称。

1. **其他常用选项**:
- `-o`: 允许用户自定义输出格式,可以选择要显示的字段。
- `-C`: 仅列出指定命令名的进程。
- `-u`: 列出指定用户的进程。
- `-k`: 列出指定进程组的进程。
- `-r`: 列出正在运行的进程。

这些选项和输出标志可以组合使用,以便获取所需的信息。要了解更多选项和输出格式,你可以查阅`ps`命令的手册页,使用`man ps`命令或者`ps --help`查看可用选项。
常用命令: ps -eLo pid,tid,%cpu,%mem,psr,comm
cpu load 1S 打印一次: mpstat -P ALL 1

linux动态库测试程序

step

在编译动态库时,您需要使用`-shared`选项来告诉编译器生成共享库,同时使用`-fPIC`选项确保生成位置无关的代码。下面是一个简单的示例:

1
2
gcc -o sum.o -c -fPIC sum.c
gcc -o libsum.so -shared sum.o
这里假设您的源文件名为`sum.c`。第一行将`sum.c`编译成一个位置无关的目标文件`sum.o`,而第二行将其链接成共享库`libsum.so`。 如果您要指定链接时的库的名称,可以使用`-o`选项。例如:
1
gcc -o libmylibrary.so -shared sum.o
这将生成名为`libmylibrary.so`的共享库。 如果您的动态库依赖于其他库,您可能需要通过`-l`和`-L`选项来指定链接库的名称和库的路径。例如,如果您的动态库依赖于`libm`,则可以这样编译:
1
gcc -o libsum.so -shared sum.o -lm
这里的`-lm`表示链接数学库。 最终,如果您的测试程序也在一个单独的文件中,您可以使用以下命令来编译它:
1
gcc -o test_sum test_sum.c -ldl -lsum -L.
这里,`-lsum`表示链接`libsum.so`,而`-L.`表示在当前目录中查找库。请确保在运行测试程序之前,系统能够找到动态库,可以通过设置`LD_LIBRARY_PATH`环境变量或将动态库放在系统库路径下来实现。

example

libSum.so

‘’’C
#include <stdio.h>
extern “C”
{
int Sum(int a,int b)
{
printf(“Input a = %d,b= %d\n”,a,b);
return a+b;
}
}
//Visual Studio 2022 打开 C++ linux创建控制台工程,然后选择生成so动态库,连接远程linux,生成不同平台的.so
‘’’
main.c:
‘’’C
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
extern int Sum(int a,int b);
int main(void)
{
printf(“Result of Sum3,4() : %d\n”,Sum(3,4));
return 0;
}
‘’’
编译main.c sudo cp libSum.so /usr/lib
gcc -o main main.c -ldl -lSum -L.

配置实时进程的方法

‘’’C
/* 在Linux系统中,可以通过以下步骤将一个进程配置为实时进程:

在编译程序时,添加实时标志:-pthread -lrt
在程序代码中使用实时调度策略:
cpp

Copy code

#include <sched.h>

// 在主线程中
struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &param);
这会将主线程设置为FIFO实时调度。

在程序启动前,使用chrt命令将其优先级设为最大:
Copy code

chrt -f -p 99 ./your_program
将程序进程锁定到特定CPU核:
Copy code

taskset 0x1 ./your_program
这会锁定到核1上。

调整实时调度器参数:
在/etc/security/limits.conf中加入:

Copy code

@users       -       rtprio     99
禁用地址空间随机化:
Copy code

echo 0 > /proc/sys/kernel/randomize_va_space
通过以上步骤,就可以获得较高的实时性能。当然,还需要避免在程序中有长时间的阻塞和等待。

Copy

chrt -f -p 99 ./your_program 和nice -n -20 ./your_program 是一样的效果吗 如果不是有什么区别呢

PZ
chrt 和 nice 这两个命令都可以影响 Linux 进程的调度优先级,但有一些区别:

chrt 用于设置实时优先级,nice 用于设置普通优先级
chrt 可以将进程优先级设置为 1-99 的实时范围,会使用实时调度策略如 SCHED_FIFO。nice 的范围是 -20 到 19,使用普通的调度策略。

chrt 优先级更高
chrt 设置的 1-99 优先级高于 nice 设置的 -20 到 19 优先级。实时进程总会抢占普通进程。

chrt 效果暂时,nice 效果持久
chrt 设置只对当前shell有效,进程结束后优先级失效。nice 设置会持久保存到进程结束。

chrt 能绑核,nice 不能
chrt 可以通过 -a 参数将进程绑定到某个 CPU 核上,nice 不提供这个功能。

所以 chrt -f -p 99 和 nice -n -20 效果上不是完全一致的:

chrt 会启用实时调度,且优先级范围高于 nice。
chrt 的优先级设置不会持久化,nice 会持久化。
chrt 可以绑核,nice 不可以。
需要根据实际场景选择使用最合适的命令来设置优先级 */

‘’’

patch generate methods

‘’’C
为每一个被修改的文件分别生成对应的patch文件,而不是把所有修改放在一个patch里。

可以通过以下方法实现:

利用git diff的--name-only选项先查看这次修改了哪些文件:
Copy code

git diff --name-only
这会输出所有的被修改的文件名。

然后对每个文件分别进行diff,重定向到各自的patch文件:
Copy code

git diff HEAD file1 > file1.patch
git diff HEAD file2 > file2.patch
重复这个过程,直到所有被修改的文件都有了对应的patch文件。
最后可以用git apply分别应用这些patch来还原一部分的修改。
这样就可以非常方便地将一次修改分解为对各个文件分别的patch文件。

这种方式在需要分别提交修改的不同部分到代码库时非常有用。

‘’’

linux use tips

  • cat /proc/cmdline 可以查看系统的启动参数
    • console=ttyLF0,115200 root=/dev/mmcblk0p2 rootwait rw earlycon
    • 也可以通过 dmesg | grep “Kernel command line”
  • 可以在uboot命令行中printenv bootargs打印当前的变量内容
    • 内容如下 bootargs=root=/dev/ram rw earlycon loglevel=7
    • setenv bootargs “root=/dev/ram rw earlycon loglevel=7 printk.time=y initcall_debug” 然后 saveenv 接着reset
    • 修改 Kernel 的 Bootargs:添加 printk.time=y initcall_debug 到 bootargs 中,以便查看每个模块的启动耗时

NXP Linux startup process analysis

uboot step

under the folder /git/arch/arm/cpu/armv8/start.S  .global _start  -> bl _main -> /git/arch/arm/cpu/lib/crt0_64.S ENTRY(_main) ->

->bl board_init_f (common/board_f.c, static const init_fnc_t init_sequence_f[]) ->b relocate_code (arch/arm/lib/relocate_64.S)->c_runtime_cpu_setup (arch/arm/cpu/armv8/start.S) ->board_init_r (common/board_r.c, static init_fnc_t init_sequence_r[]) 

[经验] 基于armv8架构对u-boot进行启动流程分析(一)以下为链接
https://bbs.elecfans.com/jishu_2282359_1_1.html
[经验] 基于armv8架构对u-boot进行启动流程分析(二)以下为链接
https://www.ws-dc.com/jishu_2282360_1_1.html
uboot启动流程(3)
https://adtxl.com/index.php/archives/757.html

内核启动先导知识
https://zhuanlan.zhihu.com/p/522195519

ArmV8启动知识梳理

https://bbs.elecfans.com/jishu_2282359_1_1.html
Alt text
上图详细概括了arm官方推荐的armv8的启动层次结构:
官方将启动分为了BL1,BL2,BL31,BL32,BL33阶段,根据顺序,芯片启动后首先执行BL1阶段代码,接着验签启动BL2,BL2根据具体设计启动BL31或者BL33,BL32只有在有BL31时才可能会存在并被验签加载启动。
armv8分为Secure World和Non-Secure World(Normal World),四种异常级别从高到低分别为EL3,EL2,EL1,EL0。
Secure World就是可以执行可信的firmware和app,比如密码支付,指纹识别等一系列依赖安全保证的服务。
Non-Secure World就是我们常见的u-boot,linux,qnx等裸机程序或者操作系统。

  • EL3具有最高管理权限,负责安全监测和安全模式切换。
  • EL2主要提供了对虚拟化的支持。
  • EL1是一个特权模式,能够执行一些特权指令,用于运行各类操作系统,在安全模式则是可信任OS。
  • EL0是无特权模式,所有APP应用都在EL0。

上图中的BL1,BL2,BL31,BL32,BL33分别对应如下功能:

  • BL1:是一切信任的根,一般就是固化在ROM中的一段启动加载代码,用于引导bl2,并对bl2进行验签保证可信任执行;
  • BL2:一般是在flash中的一段可信安全启动代码,它的可信建立在bl1对它的验证,主要完成一些平台相关的初始化,比如对ddr的初始化等,并在完成初始化后寻找BL31或者BL33进行执行;如果找到了BL31则不会继续调用BL33,如果没有BL31则BL33必须有;
  • BL31:BL31不像BL1和BL2是一次性运行的,它作为最后一道可信任固件存在,在系统运行时通过smc指令陷入EL3调用系统安全服务或者在Secure World和Non-Secure World之间进行切换;在完成BL31初始化后会去寻找BL32或者BL33进行验签后加载执行;
  • BL32:OPTee OS + 安全app,它是一个可信安全的OS运行在EL1并在EL0启动可信任APP(上述的指纹验证等app),并在Trust OS运行完成后通过smc指令返回- - BL31,BL31切换到Non-Seucre World继续执行BL33;
  • BL33:非安全固件,也就是我们常见的UEFI firmware或者u-boot也可能是直接启动Linux kernel;
    启动BL1,BL2,BL31,BL32则是一个完整的ATF信任链建立流程(ARM Trusted Firmware),像常见的PSCI(Power State Coordination Interface)功能则是在ATF的BL31上实现;

最后一张图完整展示整个调用流程:
Alt text
BL2根据是否存在BL31和BL32可选择性的加载不同firmware;
综上所述可知u-boot是一个运行在非安全世界的bootloader,负责加载各类操作系统,并提供丰富的驱动接口;并根据是否存在安全固件还可以进行不同的boot流程,如下。
u-boot,u-boot-spl,u-boot-tpl的关系:
对于一般嵌入式而言只需要一个u-boot作为bootloader即可,但是在小内存,或者有atf的情况下还可以有spl,tpl;
spl:Secondary Program Loader,二级加载器
tpl:Tertiary Program Loader,三级加载器
出现spl和tpl的原因最开始是因为系统sram太小,rom无法在ddr未初始化的情况下一次性把所有代码从flash,emmc,uxx等搬运到sram中执行,也或者是flash太小,无法完整放下整个u-boot来进行片上执行。所以u-boot又定义了spl和tpl,spl和tpl走u-boot完全相同的boot流程,不过在spl和tpl中大多数驱动和功能被去除了,根据需要只保留一部分spl和tpl需要的功能,通过CONFIG_SPL_BUILD和CONFIG_TPL_BUILD控制;一般只用spl就足够了,spl完成ddr初始化,并完成一些外设驱动初始化,比如u,emmc,以此从其他外围设备加载u-boot,但是如果对于小系统spl还是太大了,则可以继续加入tpl,tpl只做ddr等的特定初始化保证代码体积极小,以此再次从指定位置加载spl,spl再去加载u-boot。
从目前来看,spl可以取代上图中bl2的位置,或者bl1,根据具体厂商实现来决定,有一些芯片厂商会将spl固化在rom中,使其具有从emmc,u
等设备加载u-boot或者其他固件的能力。
当然在有atf的情况下可以由atf加载u-boot,或者由spl加载atf,atf再去加载u-boot。甚至在快速启动的系统中可以直接由spl启动加载linux等操作系统而跳过启动u-boot;在上图中arm官方只是给出了一个建议的启动信任链,具体实现都需要芯片厂商来决定

LinuxMemoryManage

Memory management is described and explained in detail next.

why we need memory management

For example, if a operating system have not memory management,the hardware memory will be directly accessed when the application need use memory, and this may result in other applications not being able to use the memory area and crush the system.In addition, if several applications require a large amount of memory, but the memory is not allocated and freed properly, it may lead to memory fragmentation, which may reduce the performance of the system. Therefore, memory management is a very important part of the operating system.

thread management

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sched.h>
#include <pthread.h>

static int set_affinity(pthread thread,int cpu_core)
{
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(cpu_core,&cpu_set);

return pthread_setaffinity_np(thread,sizeof(cpu_set_t),&cpuset);
}

int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg, int policy, int prio, int cpu_core)
{
struct sched_param schedp;
pthread_attr_t attr;
//cpu_set_t set;
int ret;

pthread_attr_init(&attr);
memset(&schedp, 0, sizeof(schedp));

ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if (ret) {
error("pthread_attr_setinheritsched\n", ret);
return -1;
}

ret = pthread_attr_setschedpolicy(&attr, policy);
if (ret) {
error("pthread_attr_setschedpolicy\n", ret);
return -1;
}

schedp.sched_priority = prio;
ret = pthread_attr_setschedparam(&attr, &schedp);
if (ret) {
error("pthread_attr_setschedparam\n", ret);
return -1;
}

ret = pthread_create(pth, &attr, func, arg);
if (ret) {
error("pthread_create\n", ret);
return -1;
}

ret = set_affinity(*pth,cpu_core);
return 0;
}

void set_affinity_public(int cpu_core)
{
int policy = 0;
struct sched_param pthread_param;
pid_t thread_id = syscall(SYS_gettid);
pthread_getschedparam(pthread_self(),&policy,&pthread_param);
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(cpu_core,&cpu_set);

if(0 != sched_setaffinity(thread_id,sizeof(cpu_set_t),&cpuset))
{
printf("thread %d set success core %d",thread_id,cpu_core);
}
}

thread task table

pipeline timing test(八级流水线)

‘’’C
for(int i;i <1000000000,i++)
{
fact *= i;
}

for(int i;i <1000000000,i+=8)
{
fact0 *= i;
fact1 *= i+1;
fact2 *= i+2;
fact3 *= i+3;
fact4 *= i+4;
fact5 *= i+5;
fact6 *= i+6;
fact7 *= i+7;
}
‘’’

  • 实际测量数据 : 第一个耗时大概5s左右,第二个耗时1.3s

  • 原因分析:即使在使用流水线技术的情况下,对于不同类型的计算和循环,你也不一定会看到线性的性能增长,尤其是在一些特定的情况下,因为流水线技术本身存在一些限制。

  • 在你的例子中,第一个循环是一个简单的累积乘法运算,而第二个循环则是对于每次迭代同时进行了 8 个乘法运算。在第二个循环中,尽管你利用了流水线并行处理 8 个不相关的乘法操作,但仍然受到了数据相关性和其他因素的限制。

  • 尽管处理器在第二个循环中可以并行处理多个操作,但也有一些因素可能限制了性能增长:

  • 数据相关性和依赖:即使你并行处理了 8 个操作,但在多数情况下,这些操作依然存在数据相关性,可能导致某些乘法操作需要等待之前的操作结果,从而限制了流水线的效率。

  • 资源竞争:在同时处理多个操作时,各个乘法操作之间可能会竞争同样的资源(比如寄存器),造成一定的资源争用,降低流水线效率。

  • 其他因素:像分支预测、数据访问模式等因素也可能对性能造成一定的影响。

  • 虽然你利用了流水线并行处理多个操作,但并不是所有类型的计算都能够简单地获得线性的性能提升。对于某些类型的任务,流水线技术可能并不能完全发挥其优势。针对这种情况,需要更深入地了解处理器的特性、任务本身的特性以及代码的优化,以最大化地利用流水线并行性带来的性能优势。

Linux Command

mpstat -P ALL 1 命令用于显示每个CPU的性能统计信息,包括软中断等。下面是命令输出的详解:

1
2
3
4
5
6
7
8
Linux 5.4.0-81-generic (hostname)  01/31/2024  _x86_64_ (4 CPU)

09:35:33 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
09:35:34 PM all 4.25 0.00 4.25 0.00 0.00 0.00 0.00 0.00 0.00 91.50
09:35:34 PM 0 2.97 0.00 2.97 0.00 0.00 0.00 0.00 0.00 0.00 94.06
09:35:34 PM 1 4.97 0.00 4.97 0.00 0.00 0.00 0.00 0.00 0.00 90.06
09:35:34 PM 2 5.97 0.00 5.97 0.00 0.00 0.00 0.00 0.00 0.00 88.06
09:35:34 PM 3 2.97 0.00 2.97 0.00 0.00 0.00 0.00 0.00 0.00 94.06

每一行的含义如下:

  • Linux 5.4.0-81-generic (hostname): 显示了Linux内核版本和主机名。

  • 01/31/2024: 显示了当前日期。

  • x86_64 (4 CPU): 显示了系统架构和CPU核心数量。

  • 09:35:33 PM: 显示了当前的时间戳。

  • CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle: 列出了不同的CPU使用率统计项。

    • %usr: 用户空间程序的CPU使用率。
    • %nice: 优先级较高的用户空间程序的CPU使用率。
    • %sys: 内核空间程序的CPU使用率。
    • %iowait: CPU等待I/O完成的时间百分比。
    • %irq: 处理硬中断的CPU使用率。
    • %soft: 处理软中断的CPU使用率。
    • %steal: 被虚拟化环境偷走的CPU时间。
    • %guest: 运行虚拟机的CPU时间。
    • %gnice: 优先级较高的NICE值的用户空间程序的CPU使用率。
    • %idle: CPU处于空闲状态的时间百分比。
  • all 4.25 0.00 4.25 0.00 0.00 0.00 0.00 0.00 0.00 91.50: 这一行是所有CPU的平均统计。例如,用户空间程序使用了4.25%,系统空间程序使用了4.25%,空闲时间为91.50%。

  • 0 2.97 0.00 2.97 0.00 0.00 0.00 0.00 0.00 0.00 94.06: 这一行是第一个CPU的具体统计信息,包括用户空间、系统空间、空闲时间等。

  • 1 4.97 0.00 4.97 0.00 0.00 0.00 0.00 0.00 0.00 90.06: 同上,但是是第二个CPU的统计信息。

  • 2 5.97 0.00 5.97 0.00 0.00 0.00 0.00 0.00 0.00 88.06: 同上,但是是第三个CPU的统计信息。

  • 3 2.97 0.00 2.97 0.00 0.00 0.00 0.00 0.00 0.00 94.06: 同上,但是是第四个CPU的统计信息。

这个命令的输出提供了每个CPU的详细性能统计信息,可用于监控系统中的CPU利用率情况。

perf命令

perf list | grep irq 输出中,列举了一些与中断(irq)相关的事件。对于软中断,主要关注 irq:softirq_entryirq:softirq_exitirq:softirq_raise 事件。

  1. irq:softirq_entry

    • 表示软中断开始执行的事件。当内核启动执行软中断时,会记录这个事件。
  2. irq:softirq_exit

    • 表示软中断执行结束的事件。当软中断执行完成后,会记录这个事件。
  3. irq:softirq_raise

    • 表示软中断被触发的事件。当软中断被激活时,会记录这个事件。

针对软中断的分析,可以使用以下步骤:

1. 使用 perf record 捕获软中断事件:

1
sudo perf record -e irq:softirq_entry -e irq:softirq_exit -e irq:softirq_raise -a

这会记录系统范围内软中断相关的事件。

2. 使用 perf report 查看分析报告:

1
sudo perf report

在报告中,你可以查看软中断相关的信息,了解软中断的执行时间、次数等。

3. 使用 perf script 输出文本信息:

1
sudo perf script > perf_script.txt

这会将详细的性能数据输出到 perf_script.txt 文件中,你可以在文本文件中搜索软中断相关的信息。

4. 使用 perf top 查看实时性能数据:

1
sudo perf top

perf top 提供了实时的性能数据,可以用于监视系统中的软中断活动。

注意事项:

  • 请根据你的系统和内核版本调整命令和选项,确保其兼容性。
  • 软中断的具体含义和影响可能取决于系统的配置和应用程序的特性。你可能需要进一步了解系统的软中断处理机制和软中断的触发方式。

这些步骤应该能够帮助你获取有关软中断的性能数据并进行分析。

性能分析命令

  • trace -p pid //分析进程的调用关系和开销
  • irqtop //irqtop显示
  • lsirq //列举所有irq
  • mpstat -P ALL 1 //1s显示一次所有信息中断,软中断等
  • cat /proc/interrupts
  • cat /proc/softirq
  • cat /proc/irq
  • cat /proc/irq/90/smp_affinity
  • pidstat -t -p 416 //显示pid 416的状态
  • perf list | grep irq //列举所有可以分析的irq事件,其中perf record -h是查看命令
  • ps -T -p 416 //ps –help all 显示pid 416的相关信息

ARMv8Arch

寄存器

AArch64执行状态提供了32个在任何时间任何特权级下都可访问的64位的通用寄存器。

S32R41 startup

  • FBL load the image to sram, and will change the pc pointer to M7 bootloader and then control the A53 startup(special register).

Makefile

Makefile 培训教程

Chapter 1: Makefile 简介和必要性

1.1 什么是 Makefile

Makefile 是一种文本文件,用于定义如何构建和编译软件项目。它包含了一系列规则,描述了源文件如何转化为目标文件,以及构建过程中使用的命令。

1.2 为什么需要 Makefile

Makefile 自动化了构建过程,减少了手动编译的复杂性,提高了开发效率。它能够根据文件的依赖关系自动决定哪些文件需要重新构建,从而确保项目的正确编译和构建。

1.3 Makefile vs CMake vs XMake

Makefile、CMake 和 XMake 都是构建工具,用于管理软件项目的构建过程。它们之间的主要区别在于语法和功能上的差异。Makefile 是一种基本的构建工具,CMake 提供了更高级的构建和配置功能,而 XMake 则专注于跨平台构建。

1.4 Makefile 的优点

  • 简单:Makefile 的语法相对简单,易于学习和使用。
  • 高效:通过自动化构建过程,减少了手动操作,提高了编译效率。
  • 灵活:可以根据项目的需要定制构建规则和命令。
  • 可移植性高:Makefile 在不同的操作系统和环境中都能工作,确保了项目在不同平台上的一致性。

1.5 Makefile 的历史和演进

GNU Make 是一个常用的 Make 工具,它是在 Unix 系统上发展起来的。随着软件开发的发展,出现了许多改进版本和替代工具,如 BSD Make、GNU Make、XMake 等,以满足不同项目的需求。

Chapter 2: Makefile 的基本结构和语法

2.1 Makefile 的基本结构详解

Makefile 由一系列规则组成,每个规则描述了如何将源文件转换为目标文件。规则由目标、依赖和命令三部分组成。

  • 目标(target):表示要生成的文件,可以是可执行文件、中间文件等。
  • 依赖(dependencies):表示生成目标所需的文件,当依赖文件发生变化时,目标将被重新构建。
  • 命令(commands):表示生成目标的具体步骤,使用制表符开头,并在命令之间用换行分隔。

示例:

1
2
3
# 规则:生成目标文件 main.o
main.o: main.c
$(CC) $(CFLAGS) -c $< -o $@

2.2 注释和变量

  • 注释使用#符号,用于添加解释和注释,提高 Makefile 的可读性。
  • 变量用于存储数据,可以是文件名、编译器选项等,以便在 Makefile 中重复使用。

Makefile使用Tips

怎么把换行符CRLF替换为LF

sed -i ‘s/\r$///‘ file1.sh

递归查找源文件和头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
//Common.mk
#define find_c_files
$(wildcard $(1)/*.c) $(foreach dir,$(wildcard $(1)/*),$(call find_c_files,$(dir)))
#endef

#define find_h_files
$(wildcard $(1)/*.h) $(foreach dir,$(wildcard $(1)/*),$(call find_h_files,$(dir)))
#endef

//Makefile
SRC := $(call find_c_files,$(DIR)/code)
INC := $(call find_h_files,$(DIR)/code)
INC_DIR := $(sort $(dir $(call find_h_files,$(DIR)/code)))

personalNote

Precautions For Inter-core Data Transfer

the cache needs to be especially careful because it can cause your data to be accessed incorrectly. If core A needs to access the memory of core B, this section of core B memory needs to be careful if there is a cache, which is generally not recommended 

SPI调试总结

SPI时序可能出现问题,需要用逻辑分析仪Kingst VIS或者示波器查看波形变化,为什么出现延时情况,读写寄存器为什么会出现这么大的时间延时。结果发现和系统调用有很大的关系,xxx.elf的进程在运行过程中采用的是默认的优先级配置的nice值默认为0,会出现被抢占的情况,所以整体的延时会出现60us的情况。正常情况下是7-8us.整个配置MMIC的时间。

知乎学习链接

https://www.zhihu.com/people/ljgibbs/posts

https://www.zhihu.com/people/lgjjeff

‘’’C
//tcp server,can reconnection and recv data from tcp client
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#define PORT 11011
#define IP_ADDR “192.168.30.60”

int main(){

int server_fd, client_fd;
struct sockaddr_in server_addr,client_addr; 

// 创建 socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if(server_fd < 0){
    printf("Error creating socket!");
    return 1;
}

// 设置地址与端口信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(IP_ADDR); 
server_addr.sin_port = htons(PORT);

// 绑定socket与地址信息 
if(bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
   printf("Bind failed!");
   return 1;
}

// 开始监听
if (listen(server_fd, 5) < 0){
    printf("Listen failed!");
    return 1;
}
 
while(1){
    socklen_t client_len = sizeof(client_addr);
      // 等待客户端连接请求 
    client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
      if(client_fd < 0){
      continue;
      }
    
    // 设置 client_fd 为非阻塞模式
    fcntl(client_fd, F_SETFL, O_NONBLOCK);
  
       while(1){

        // 尝试接收数据
        char buffer[1024];        
        int byte_num = recv(client_fd, buffer, 1024, 0);
        // 连接已关闭
        if(byte_num == 0){
            close(client_fd);
            break;
        }
      
        // 打印接收到的数据
        //if(byte_num > 0){
          //  printf("Received data: %s", buffer); 
        //}

        // 遍历缓冲区每个字节
        for(int i=0; i < byte_num; i++) {

            // 将字节转换为整数打印 
            printf("%x ", (int)buffer[i]); 

        } 

        printf("\n");


    }

    // 关闭客户端 socket
    close(client_fd); 
}

return 0;

}
‘’’

ArmTrustFirmware

主要从四个部分去讲解

一、 安全引导的作用
二、 安全引导的原理
三、 ATF的启动过程框架
四、 ATF的启动过程Code解析

什么是ATF

ARM Trusted Firmware中的Trusted Firmware-A(TF-A),是其中的一个类别、项目。这个是在armV8中引入的安全解决方案。它主要包括启动和运行过程中的特权级划分,对ArmV7中的TZ进行了提高,主要是补充了启动过程中信任链的传导,细化运行过程中的特权级区间。

安全引导/启动

什么是安全引导/启动

指的是在系统的启动过程中,使用链式验证电子签名的方式来验证系统里的重要镜像文件的可靠性,然后再加载镜像文件的引导过程。

为什么要安全引导/启动

它可以保护二级厂商系统的独立性和完整性,在V8架构中arm提供了arm可信固件ATF。

目的

Bootloader、kernel、TEE os的启动都由ATF来加载和引导。对于V8,bootloader、kernel、TEE os镜像文件的验签工作都是在ATF中完成的。

启动流程以及阶段划分

分为两种类型:冷启动(restart)和热启动(reset)
1
2
3
4
5
6
7
五个步骤/阶段:

1. BL1 - AP Trusted ROM(normal is BootRom)
2. BL2 - Trusted Boot Firmware (normal is Trusted Bootloader)
3. BL31- EL3 Runtime Firmware (normal is SML,manage SMC handle and interrupt, run in secure monitor)
4. BL32- Secure-EL1 Payload (normal is TEE os Image)
5. BL33- Non-Trusted Firmware (normal is uboot,linux kernel)
ATF will output BL1,BL2,BL31,and provide BL32, BL33 interface.
I think the interface ATF provide is BL32 and BL33 can be specified, and ATF is actually a framework, it contains five procedures can be 
defined by manufacturer.