侵权投诉

Linux内核ftrace的学习

FPGA干货 2021-08-13 17:33 次阅读

目录

1. 前言

2. ARM64栈帧结构

3. 编译阶段

3.1 未开启ftrace时的blk_update_request

3.2 开启ftrace时的blk_update_request

4. 链接阶段

4.1 未开启ftrace时的blk_update_request

4.2 开启ftrace时的blk_update_request

5. 运行阶段

5.1 ftrace_init执行后的blk_update_request

5.2 设定trace函数blk_update_request

6. 钩子函数的替换过程

7.总结

参考文档

1. 前言

本文主要是根据阅码场 《Linux内核tracers的实现原理与应用》视频课程,我自己在aarch64上的实践。通过观察钩子函数的创建过程以及替换过程,理解trace的原理。本文同样以blk_update_request函数为例进行说明。

kernel版本:5.10平台:arm64

2.ARM64栈帧结构

在开始介绍arm64架构下的ftrace之前,先来简要说明一下arm64栈帧的相关知识。arm64有31个通用寄存器r0-r30,其中r0-r7用于Parameter/result 寄存器; r29为Frame Pointer寄存器,r30为Link寄存器,指向上级函数的返回地址;SP为栈指针。将以如下代码为例,说明它的栈帧结构:

/*

* ARCH: armv8

* GCC版本:aarch64-linux-gnu-gcc (Linaro GCC 5.4-2017.01) 5.4.1 20161213

*/

intfun2(int c,int d)

{

return0;

}

intfun1(int a,int b)

{

int c = 1;

int d = 2;

fun2(c, d);

return0;

}

intmain(int argc,char **argv)

{

int a = 0;

int b = 1;

fun1(a,b);

}

aarch64-linux-gnu-objdump -d a.out 反汇编后的结果为:

0000000000400530 《fun2》:

/* 更新sp到fun2的栈底 */

400530: d10043ff sub sp, sp, #0x10

400534: b9000fe0 str w0, [sp,#12]

400538: b9000be1 str w1, [sp,#8]

40053c: 52800000 mov w0, #0x0 // #0

400540: 910043ff add sp, sp, #0x10

400544: d65f03c0 ret

0000000000400548 《fun1》:

/* 分配48字节栈空间,先更新sp=sp-48, 再入栈x29, x30, 此时sp指向栈顶 */

400548: a9bd7bfd stp x29, x30, [sp,#-48]!

/* x29、sp指向栈顶*/

40054c: 910003fd mov x29, sp

/* 入栈fun1参数0 */

400550: b9001fa0 str w0, [x29,#28]

/* 入栈fun1参数1 */

400554: b9001ba1 str w1, [x29,#24]

/* 入栈fun1局部变量c */

400558: 52800020 mov w0, #0x1 // #1

40055c: b9002fa0 str w0, [x29,#44]

/* 入栈fun1局部变量d */

400560: 52800040 mov w0, #0x2 // #2

400564: b9002ba0 str w0, [x29,#40]

400568: b9402ba1 ldr w1, [x29,#40]

40056c: b9402fa0 ldr w0, [x29,#44]

/* 跳转到fun2 */

400570: 97fffff0 bl 400530 《fun2》

400574: 52800000 mov w0, #0x0 // #0

400578: a8c37bfd ldp x29, x30, [sp],#48

40057c: d65f03c0 ret

0000000000400580 《main》:

/* 分配48字节栈空间,先更新sp=sp-48, 再入栈x29, x30, 此时sp指向栈顶*/

400580: a9bd7bfd stp x29, x30, [sp,#-48]!

/* x29、sp指向栈顶*/

400584: 910003fd mov x29, sp

/* 入栈main参数0 */

400588: b9001fa0 str w0, [x29,#28]

/* 入栈main参数1 */

40058c: f9000ba1 str x1, [x29,#16]

/* 入栈变量a */

400590: b9002fbf str wzr, [x29,#44]

400594: 52800020 mov w0, #0x1 // #1

/* 入栈变量b */

400598: b9002ba0 str w0, [x29,#40]

40059c: b9402ba1 ldr w1, [x29,#40]

4005a0: b9402fa0 ldr w0, [x29,#44]

/* 跳转到fun1 */

4005a4: 97ffffe9 bl 400548 《fun1》

4005a8: 52800000 mov w0, #0x0 // #0

4005ac: a8c37bfd ldp x29, x30, [sp],#48

4005b0: d65f03c0 ret

4005b4: 00000000 .inst 0x00000000 ; undefined

对应栈帧结构为:

f1e2a83e-fbba-11eb-9bcf-12bb97331649.png

总结一下:通过对aarch64代码反汇编的分析,可以得出:

1. 每个函数在入口处首先会分配栈空间,且一次分配,确定栈顶,之后sp将不再变化;

2. 每个函数的栈顶部存放的是caller的栈顶指针,即fun1的栈顶存放的是main栈顶指针;

3. 对于最后一级callee函数,由于x29保存了上一级caller的栈顶sp指针,因此不在需要入栈保存,如示例中fun2执行时,此时x29指向fun1的栈顶sp

下面我们将根据是否开启ftrace配置,并区分编译阶段、链接阶段和运行阶段,分别查看钩子函数的替换及构建情况。

3. 编译阶段

3.1 未开启ftrace时的blk_update_request

00000000000012ac 《blk_update_request》:

12ac: d10183ff sub sp, sp, #0x60

12b0: a9017bfd stp x29, x30, [sp,#16]

12b4: 910043fd add x29, sp, #0x10

12b8: a90253f3 stp x19, x20, [sp,#32]

12bc: a9035bf5 stp x21, x22, [sp,#48]

12c0: a90463f7 stp x23, x24, [sp,#64]

12c4: f9002bf9 str x25, [sp,#80]

12c8: aa0003f6 mov x22, x0

12cc: 53001c38 uxtb w24, w1

12d0: 2a0203f5 mov w21, w2

12d4: 2a1803e0 mov w0, w24

12d8: 94000000 bl 12c 《blk_status_to_errno》

...

在未使能内核配置项CONFIG_FTRACE时,反汇编blk_update_request函数可以看出,不包含钩子函数。

3.2 开启ftrace时的blk_update_request

0000000000003f10 《blk_update_request》:

3f10: d10183ff sub sp, sp, #0x60

3f14: a9017bfd stp x29, x30, [sp,#16]

3f18: 910043fd add x29, sp, #0x10

3f1c: a90253f3 stp x19, x20, [sp,#32]

3f20: a9035bf5 stp x21, x22, [sp,#48]

3f24: a90463f7 stp x23, x24, [sp,#64]

3f28: f9002bf9 str x25, [sp,#80]

3f2c: aa0003f6 mov x22, x0

3f30: 53001c38 uxtb w24, w1

3f34: 2a0203f5 mov w21, w2

3f38: aa1e03e0 mov x0, x30

3f3c: 94000000 bl 0 《_mcount》

...

在使能内核配置项CONFIG_FTRACE时,可以看到blk_update_request函数增加了如下部分:

3f3c: 94000000 bl 0 《_mcount》

那么 bl 0 《_mcount》 是由谁在何时插入的呢? 答案是编译器在编译时插入,编译选项-pg -mrecord-mcoun会在编译时在每个可trace函数插入bl 0 《_mcount》,并将所有可trace的函数放到一个__mcount_loc的section中。

通过查看blk-core.o的可重定位段,可以看到有大量的地址需要定位到_mcount函数,其中3f3c地址正是位于blk_update_request,它会在链接阶段被重定位到_mcount函数的地址。

ubuntu@VM-0-9-ubuntu:~/qemu/kernel/linux/block$ aarch64-linux-gnu-objdump -r blk-core.o | grep _mcount

0000000000000014 R_AARCH64_CALL26 _mcount

000000000000005c R_AARCH64_CALL26 _mcount

00000000000000ac R_AARCH64_CALL26 _mcount

0000000000000108 R_AARCH64_CALL26 _mcount

0000000000000164 R_AARCH64_CALL26 _mcount

00000000000001bc R_AARCH64_CALL26 _mcount

0000000000000214 R_AARCH64_CALL26 _mcount

...

0000000000003f3c R_AARCH64_CALL26 _mcount

...

我们还可以看到,blk-core.o有一个.rela__mcount_loc的可重定位段,里面存放了所有需要可trace函数中需要重定位到函数_mcount的地址。

ubuntu@VM-0-9-ubuntu:~/qemu/kernel/linux/block$ aarch64-linux-gnu-objdump -r blk-core.o

...

RELOCATION RECORDS FOR [__mcount_loc]:

OFFSET TYPE VALUE

0000000000000000 R_AARCH64_ABS64 .text+0x0000000000000014

0000000000000008 R_AARCH64_ABS64 .text+0x000000000000005c

0000000000000010 R_AARCH64_ABS64 .text+0x00000000000000ac

0000000000000018 R_AARCH64_ABS64 .text+0x0000000000000108

...

00000000000001b8 R_AARCH64_ABS64 .text+0x0000000000003f3c

...

4. 链接阶段

4.1 未开启ftrace时的blk_update_request

未使能内核配置项CONFIG_FTRACE时,链接阶段与编译阶段一样,反汇编blk_update_request函数可以看出,不包含钩子函数

4.2 开启ftrace时的blk_update_request

ffff8000104e43c8 《blk_update_request》:

ffff8000104e43c8: d10183ff sub sp, sp, #0x60

ffff8000104e43cc: a9017bfd stp x29, x30, [sp,#16]

ffff8000104e43d0: 910043fd add x29, sp, #0x10

ffff8000104e43d4: a90253f3 stp x19, x20, [sp,#32]

ffff8000104e43d8: a9035bf5 stp x21, x22, [sp,#48]

ffff8000104e43dc: a90463f7 stp x23, x24, [sp,#64]

ffff8000104e43e0: f9002bf9 str x25, [sp,#80]

ffff8000104e43e4: aa0003f6 mov x22, x0

ffff8000104e43e8: 53001c38 uxtb w24, w1

ffff8000104e43ec: 2a0203f5 mov w21, w2

ffff8000104e43f0: aa1e03e0 mov x0, x30

ffff8000104e43f4: 97ed1fde bl ffff80001002c36c 《_mcount》

ffff8000104e43f8: 2a1803e0 mov w0, w24

ffff8000104e43fc: 97fff432 bl ffff8000104e14c4 《blk_status_to_errno》

...

在链接阶段,使能内核配置项CONFIG_FTRACE时,可以看到编译阶段的如下代码

3f3c: 94000000 bl 0 《_mcount》

在链接阶段已经被替换为:

ffff8000104e43f4: 97ed1fde bl ffff80001002c36c 《_mcount》

其中_mcount函数反汇编为:

ffff80001002c36c 《_mcount》:

ffff80001002c36c: d65f03c0 ret

5. 运行阶段

5.1ftrace_init执行后的blk_update_request

(gdb) x/20i blk_update_request

0xffff8000104e43c8 《blk_update_request》: sub sp, sp, #0x60

0xffff8000104e43cc 《blk_update_request+4》: stp x29, x30, [sp,#16]

0xffff8000104e43d0 《blk_update_request+8》: add x29, sp, #0x10

0xffff8000104e43d4 《blk_update_request+12》: stp x19, x20, [sp,#32]

0xffff8000104e43d8 《blk_update_request+16》: stp x21, x22, [sp,#48]

0xffff8000104e43dc 《blk_update_request+20》: stp x23, x24, [sp,#64]

0xffff8000104e43e0 《blk_update_request+24》: str x25, [sp,#80]

0xffff8000104e43e4 《blk_update_request+28》: mov x22, x0

0xffff8000104e43e8 《blk_update_request+32》: uxtb w24, w1

0xffff8000104e43ec 《blk_update_request+36》: mov w21, w2

0xffff8000104e43f0 《blk_update_request+40》: mov x0, x30

0xffff8000104e43f4 《blk_update_request+44》: nop

0xffff8000104e43f8 《blk_update_request+48》: mov w0, w24

0xffff8000104e43fc 《blk_update_request+52》: bl 0xffff8000104e14c4 《blk_status_to_errno》

内核在start_kernel执行时,会调用ftrace_init,它会将所有可trace函数中的_mcount进行替换,如上可以看出链接阶段的 bl ffff80001002c36c 《_mcount》 已经被替换为nop指令

5.2 设定trace函数blk_update_request

执行如下命令来trace函数blk_update_request

ubuntu@VM-0-9-ubuntu:~$echo blk_update_request 》 /sys/kernel/debug/tracing/set_ftrace_filter

ubuntu@VM-0-9-ubuntu:~$echo function 》 /sys/kernel/debug/tracing/current_tracer

我们再来查看blk_update_request反汇编代码

(gdb) x/20i blk_update_request

0xffff8000104e43c8 《blk_update_request》: sub sp, sp, #0x60

0xffff8000104e43cc 《blk_update_request+4》: stp x29, x30, [sp,#16]

0xffff8000104e43d0 《blk_update_request+8》: add x29, sp, #0x10

0xffff8000104e43d4 《blk_update_request+12》: stp x19, x20, [sp,#32]

0xffff8000104e43d8 《blk_update_request+16》: stp x21, x22, [sp,#48]

0xffff8000104e43dc 《blk_update_request+20》: stp x23, x24, [sp,#64]

0xffff8000104e43e0 《blk_update_request+24》: str x25, [sp,#80]

0xffff8000104e43e4 《blk_update_request+28》: mov x22, x0

0xffff8000104e43e8 《blk_update_request+32》: uxtb w24, w1

0xffff8000104e43ec 《blk_update_request+36》: mov w21, w2

0xffff8000104e43f0 《blk_update_request+40》: mov x0, x30

0xffff8000104e43f4 《blk_update_request+44》: bl 0xffff80001002c370 《ftrace_caller》

0xffff8000104e43f8 《blk_update_request+48》: mov w0, w24

0xffff8000104e43fc 《blk_update_request+52》: bl 0xffff8000104e14c4 《blk_status_to_errno》

可以看到之前在blk_update_request的nop指令被替换成

bl 0xffff80001002c370 《ftrace_caller》

继续反汇编ftrace_caller得到如下的汇编代码:

(gdb) disassemble ftrace_caller

Dump of assembler code for function ftrace_caller:

0xffff80001002c374 《+0》: stp x29, x30, [sp,#-16]!

0xffff80001002c378 《+4》: mov x29, sp

// x30是blk_update_request的lr,-4是当前执行函数的入口地址,也就是ftrace_caller的ip

// 它将作为参数0传递给ftrace_ops_no_ops

0xffff80001002c37c 《+8》: sub x0, x30, #0x4

// 参考前面arm64栈帧结构,x29指向上一级函数blk_update_request栈顶

//[x29]指向blk_mq_end_request函数的栈顶

//[[x29]+8]为blk_mq_end_request的ip(实际是ip的下条指令)

0xffff80001002c380 《+12》: ldr x1, [x29]

0xffff80001002c384 《+16》: ldr x1, [x1,#8]

0xffff80001002c388 《+20》: bl 0xffff800010188ffc 《ftrace_ops_no_ops》

0xffff80001002c38c 《+24》: nop

0xffff80001002c390 《+28》: ldp x29, x30, [sp],#16

0xffff80001002c394 《+32》: ret

End of assembler dump.

可以看到ftrace_caller会调用ftrace_ops_no_ops,我们在ftrace_ops_no_ops源码中看到它会遍历ftrace_ops_list链表,并执行这个链表上的回调函数,这里看下ftrace_ops_list上都链接了哪些func

(gdb) p *ftrace_ops_list

$4 = {

func = 0xffff8000101a0b1c 《function_trace_call》, //ftrace_ops_list链表唯一func

next = 0xffff800011c5a438 《ftrace_list_end》, //说明ftrace_ops_list链表只有一个func

flags = 8273,

private = 0xffff800011cf94e8 《global_trace》,

saved_func = 0xffff8000101a0b1c 《function_trace_call》,

local_hash = {

notrace_hash = 0xffff800010cf7118 《empty_hash》,

filter_hash = 0xffff00000720af80,

regex_lock = {

owner = {

counter = 0

},

......

从ftrace_ops_list链表中可以看到只有一个function_trace_call函数组成,因此可以说ftrace_caller最终会调用到function_trace_call。

通过前面的分析,我们一步步找到了blk_update_request的钩子函数function_trace_call,其函数原型如下,其中参数ip指向ftrace_caller,参数parent_ip指向blk_mq_end_request:

staticvoid

function_trace_call(unsignedlong ip, unsignedlong parent_ip,

struct ftrace_ops *op, struct pt_regs *pt_regs)

下一节我们将追踪钩子函数的构造以及替换过程。

6. 钩子函数的替换过程

前面我们看到blk_update_request的nop指令被替换成bl ftrace_caller,那么此处的ftrace_caller是在哪里定义的呢?我们可以看到arch/arm64/kernel/entry-ftrace.S有如下的定义:

/*

* void ftrace_caller(unsigned long return_address)

* @return_address: return address to instrumented function

*

* This function is a counterpart of _mcount() in ‘static’ ftrace, and

* makes calls to:

* - tracer function to probe instrumented function‘s entry,

* - ftrace_graph_caller to set up an exit hook

*/

SYM_FUNC_START(ftrace_caller)

mcount_enter

mcount_get_pc0 x0 // function’s pc

mcount_get_lr x1 // function‘s lr

SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) // tracer(pc, lr);

nop // This will be replaced with “bl xxx”

// where xxx can be any kind of tracer.

#ifdef CONFIG_FUNCTION_GRAPH_TRACER

SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();

nop // If enabled, this will be replaced

// “b ftrace_graph_caller”

#endif

mcount_exit

SYM_FUNC_END(ftrace_caller)

通过 gdb可以看到ftrace_caller的反汇编代码如下:

(gdb) disassemble ftrace_caller

Dump of assembler code for function ftrace_caller:

0xffff80001002c370 《+0》: stp x29, x30, [sp,#-16]!

0xffff80001002c374 《+4》: mov x29, sp

0xffff80001002c378 《+8》: sub x0, x30, #0x4

0xffff80001002c37c 《+12》: ldr x1, [x29]

0xffff80001002c380 《+16》: ldr x1, [x1,#8]

0xffff80001002c384 《+20》: nop /*ftrace_call*/

0xffff80001002c388 《+24》: nop /*ftrace_graph_call,暂不讨论*/

0xffff80001002c38c 《+28》: ldp x29, x30, [sp],#16

0xffff80001002c390 《+32》: ret

End of assembler dump.

当执行echo blk_update_request 》set_ftrace_filter时相当于使能了blk_update_request的钩子替换标志,当执行echo function 》current_tracer时会检查这个标志,并执行替换,它会产生如下的调用链:

/sys/kernel/debug/tracing # echo function 》 current_tracer

[ 45.632002] CPU: 0 PID: 111 Comm: sh Not tainted 5.10.0-dirty #35

[ 45.632457] Hardware name: linux,dummy-virt (DT)

[ 45.632697] Call trace:

[ 45.632981] dump_backtrace+0x0/0x1f8

[ 45.633169] show_stack+0x2c/0x7c

[ 45.634039] ftrace_modify_all_code+0x38/0x118

[ 45.634269] arch_ftrace_update_code+0x10/0x18

[ 45.634495] ftrace_run_update_code+0x2c/0x48

[ 45.634727] ftrace_startup_enable+0x40/0x4c

[ 45.634943] ftrace_startup+0xec/0x11c

[ 45.635137] register_ftrace_function+0x68/0x84

[ 45.635369] function_trace_init+0xa0/0xc4

[ 45.635574] tracer_init+0x28/0x34

[ 45.635768] tracing_set_tracer+0x11c/0x17c

[ 45.635982] tracing_set_trace_write+0x124/0x170

[ 45.636224] vfs_write+0x16c/0x368

[ 45.636409] ksys_write+0x74/0x10c

[ 45.636594] __arm64_sys_write+0x28/0x34

[ 45.636923] el0_svc_common+0xf0/0x174

[ 45.637138] do_el0_svc+0x84/0x90

[ 45.637330] el0_svc+0x1c/0x28

[ 45.637510] el0_sync_handler+0x3c/0xac

[ 45.637721] el0_sync+0x140/0x180

进一步查看ftrace_modify_all_code的代码,我们可以看到如下的调用流程:

ftrace_modify_all_code(command)

--ftrace_update_ftrace_func(ftrace_ops_list_func)

|--pc = (unsignedlong)&ftrace_call

| //此处ftrace_ops_list_func为ftrace_ops_no_ops,

| //因此会返回bl ftrace_ops_no_ops给new*/

|--new = aarch64_insn_gen_branch_imm(pc, (unsignedlong)ftrace_ops_list_func,

| AARCH64_INSN_BRANCH_LINK);

--ftrace_modify_code(pc, 0, new, false)

如上,ftrace_modify_code通过修改text段,将指令ftrace_call替换为bl ftrace_ops_no_ops,此处是第一次替换;

ftrace_modify_all_code(command)

--ftrace_replace_code(mod_flags | FTRACE_MODIFY_ENABLE_FL);

--do_for_each_ftrace_rec(pg, rec) {

__ftrace_replace_code(rec, enable);

} while_for_each_ftrace_rec();

如上,会遍历每一个可trace的函数,对于使能了替换标记的函数,将其nop替换为bl ftrace_caller,此处是第二次替换,ftrace_caller也就是我们所认为的钩子函数。

7.总结

到此我们已经分析完了ftrace的各个阶段的行为,以及钩子函数的替换过程,基本上包含如下过程:

1. 编译阶段。通过编译选项 -pg -mrecord-mcount 在每个支持ftrace的函数中插入bl 0 《_mcount》指令

2. 链接阶段。会根据重定位段将bl 0 《_mcount》指令地址重定位为_mcount函数地址。

3. 运行阶段 (1)ftrace_init:会将可trace函数中的bl _mcount替换为nop指令;(2)执行echo blk_update_request 》set_ftrace_filter:会使能blk_update_request的钩子函数替换标记(nop替换为ftrace_caller); (3)执行echofunction 》 current_tracer:触发两步替换:第一步,ftrace_caller中ftrace_call被替换为ftrace_ops_no_ops;第二步,blk_update_request中的nop被替换为ftrace_caller。ftrace_caller最终会调用到function_trace_call,它会记录函数调用堆栈信息,并将结果写入 ring buffer,用户可以通过/sys/kernel/debug/tracing/trace文件读取该 ring buffer 中的内容。

最后,给出一个通过ftrace跟踪dd写入操作的例子,脚本为ftrace.sh

#!/bin/bash

debugfs=/sys/kernel/debug

echo nop 》 $debugfs/tracing/current_tracer

echo 0 》 $debugfs/tracing/tracing_on

echo $$ 》 $debugfs/tracing/set_ftrace_pid

echo function 》 $debugfs/tracing/current_tracer

#replace test_proc_show by your function name

echo ksys_write 》 $debugfs/tracing/set_ftrace_filter

echo 1 》 $debugfs/tracing/tracing_on

exec “$@”

ubuntu@VM-0-9-ubuntu:$ 。/ftrace.sh dd if=/dev/zero of=test bs=512 count=1048576

执行结果:

root@VM-0-9-ubuntu:# cat /sys//kernel/debug/tracing/trace

# tracer: function

#

# entries-in-buffer/entries-written: 102454/1048579 #P:2

#

# _-----=》 irqs-off

# / _----=》 need-resched

# | / _---=》 hardirq/softirq

# || / _--=》 preempt-depth

# ||| / delay

# TASK-PID CPU# |||| TIMESTAMP FUNCTION

# | | | |||| | |

dd-32307 [000] .... 1380661.568624: vfs_write 《-SyS_write

dd-32307 [000] .... 1380661.568626: vfs_write 《-SyS_write

dd-32307 [000] .... 1380661.568630: vfs_write 《-SyS_write

dd-32307 [000] .... 1380661.568632: vfs_write 《-SyS_write

......

责任编辑:haq

原文标题:ftrace学习笔记

文章出处:【微信号:gh_6fde77c41971,微信公众号:FPGA干货】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
分享:

评论

相关推荐

STM32 Linux开发板推荐 ,入门进阶必备!

推荐一款适合入门进阶学习的Linux开发板:华清远见FS-MP1A开发板(STM32MP157开发板....
发表于 10-22 18:51 4次 阅读

【视频】华清远见stm32mp157开发入门指导(7讲)

关于FS-MP1A开发板(stm32mp157): FS-MP1A开发板是华清远见最新自主研发的一....
发表于 10-22 18:50 1次 阅读

一图了解华清远见STM32MP157开发板学习资源优势

一图了解华清远见STM32MP157开发板学习资源优势(教程+视频+项目): 资料说明及更新情....
发表于 10-22 18:49 3次 阅读

linux spi应用层驱动以及回环测试代码

linux spi应用层驱动以及回环测试代码
发表于 10-22 15:47 9次 阅读

给树莓派添加一个开、关机按键(原创)

给树莓派添加一个开、关机按键(原创)声明关键词问题起因解决方案一、实现方式二、实现原理三、改进方案声....
发表于 10-22 10:06 12次 阅读
给树莓派添加一个开、关机按键(原创)

分享!基于Zynq-7010/7020的多路千兆网口实现方案

前 言:本文基于以太网接口在工业场合的大量使用,特别是工业控制、仪器仪表等领域,结合Xilinx Zynq-7000所具备的丰富设计资源...
发表于 10-22 09:43 101次 阅读

基于ARM Linux的WiFi智能终端门禁系统

引言 随着社会经济的快速发展,人们对室内人身财产安全要求越来越高,门禁系统作为智能建筑安防自动化体系中必不可少的一部分[1...
发表于 10-22 09:27 404次 阅读

一文读懂什么是Linux驱动呢

什么是Linux驱动? Linux驱动程序需要掌握哪些内容呢? ARM处理器体系架构是由哪些部分组成的? ...
发表于 10-22 08:43 0次 阅读

香橙派全志芯片开发板下载交叉编译工具链说明

香橙派开发板以处理器分类,包含全志H2、全志H3、全志H5、全志H6等系列,下文以全志H3芯片的开发板为例,对交叉编译工具链的...
发表于 10-21 17:35 101次 阅读
香橙派全志芯片开发板下载交叉编译工具链说明

嵌入式linux开发视频下载

嵌入式Linux视频教程:ed2k://|file|Tiny6410%E5%9B%BD%E5%B5%....
发表于 10-21 13:21 7次 阅读
嵌入式linux开发视频下载

嵌入式linux开发视频下载

嵌入式Linux视频教程:ed2k://|file|Tiny6410%E5%9B%BD%E5%B5%....
发表于 10-21 13:21 7次 阅读
嵌入式linux开发视频下载

嵌入式软件未来发展趋势

虽说嵌入式未来发展一片大好,但也会有一些人很想多了解一下嵌入式,毕竟之后要学习嵌入式的话,也要多了解....
发表于 10-21 13:06 15次 阅读
嵌入式软件未来发展趋势

【嵌入式实验】《嵌入式开发工具使用》

嵌入式开发工具使用一.实验目的二.实验内容三.预备知识四.实验设备及工具(包括软件调试工具)五.实验....
发表于 10-21 13:06 8次 阅读
【嵌入式实验】《嵌入式开发工具使用》

嵌入式Linux NFS

文章目录前言服务器配置嵌入式设备挂载微信公众号前言网络文件系统(英语:Network File Sy....
发表于 10-21 12:51 5次 阅读
嵌入式Linux NFS

小白找工作:嵌入式工程师(从单片机到嵌入式,我该投哪个岗位)

小白找工作:嵌入式工程师前言从单片机到嵌入式,我该投哪个岗位前言好久没有写博客了,这段时间主要是去做....
发表于 10-21 12:51 19次 阅读
小白找工作:嵌入式工程师(从单片机到嵌入式,我该投哪个岗位)

嵌入式软件工程师成长方向的思考

最近有点空闲,总结下嵌入式工程师所需要掌握的技能,及成长方向。主体知识:C语言、数据结构 + 算法、....
发表于 10-21 12:36 8次 阅读
嵌入式软件工程师成长方向的思考

嵌入式linux根文件系统损坏恢复方法

昨晚在对开发板的文件进行复制操作时遇到卡死,强制重启之后发现进不了命令行模式,输入回车键一直提示:c....
发表于 10-21 12:36 6次 阅读
嵌入式linux根文件系统损坏恢复方法

嵌入式linux的开发流程以及linux应用层内容

嵌入式linux开发流程:1.搭建前期的开发环境,例如搭建linux主机环境,交叉编译器的安装,还有....
发表于 10-21 12:36 7次 阅读
嵌入式linux的开发流程以及linux应用层内容

树莓派1:嵌入式开发概述

嵌入式开发概述1.嵌入式硬件选型:嵌入式即嵌入式系统,IEEE对其定义是用于控制,监视或者辅助操作机....
发表于 10-21 12:06 12次 阅读
树莓派1:嵌入式开发概述

嵌入式开发中常用的几种通信接口总结

关注、星标公众号,直达精彩内容在嵌入式系统中,板上通信接口是指用于将各种集成电路与其他外围设备交互连....
发表于 10-21 11:21 7次 阅读
嵌入式开发中常用的几种通信接口总结

嵌入式系统移植之TFTP配置方法(自己学习总结)

TFTP服务TFTP是用来下载远程文件的最简单网络协议,它其于UDP协议而实现。嵌入式linux的t....
发表于 10-21 11:08 4次 阅读
嵌入式系统移植之TFTP配置方法(自己学习总结)

Linux嵌入式学习过程

Linux嵌入式学习过程循序渐进学习嵌入式开发技术一、练好基本功二、嵌入式Linux应用开发误区一、....
发表于 10-21 11:07 8次 阅读
Linux嵌入式学习过程

嵌入式Linux开发环境搭建之安装Ubuntu

最近打算重新自学 linux 嵌入式,既然要重来,那就得从头开始,linux 开发第一件事就是搭建 ....
发表于 10-21 11:06 11次 阅读
嵌入式Linux开发环境搭建之安装Ubuntu

嵌入式分层概括总结

最近重新进入嵌入式领域,有必要对嵌入式分层架构有一个清晰的理解。经过多方查阅以及个人的理解,本人对嵌....
发表于 10-21 10:51 8次 阅读
嵌入式分层概括总结

嵌入式软件开发学习资料

黑发不知勤学早,白首方悔读书迟。适合学习嵌入式软件开发的资料,除了粤嵌的,其他的我都看过。非嵌入式方....
发表于 10-21 10:51 7次 阅读
嵌入式软件开发学习资料

嵌入式学习之线程

线程概述一个程序中的多个执行路线叫做线程,线程是一个进程内部的控制序列。所有的进程都至少有一个执行线....
发表于 10-21 10:51 4次 阅读
嵌入式学习之线程

【嵌入式实验】《嵌入式数据库 sqlite 移植及使用》

嵌入式数据库 sqlite 移植及使用一、实验目的二.实验内容三.预备知识四.实验设备及工具(包括软....
发表于 10-21 10:51 6次 阅读
【嵌入式实验】《嵌入式数据库 sqlite 移植及使用》

【嵌入式技能树】

嵌入式工程师需要哪些技能书/技能加点? 学习程度:熟悉 < 有过经验 < 熟练 < 精通文章目录通用....
发表于 10-21 10:21 8次 阅读
【嵌入式技能树】

嵌入式Linux开发学习如何入门、如何深入?

嵌入式Linux开发学习如何入门、如何深入?学习步骤如下:1、Linux 基础安装Linux操作系统....
发表于 10-21 10:21 8次 阅读
嵌入式Linux开发学习如何入门、如何深入?

嵌入式搭建ftp服务器

嵌入式ftp下载源码git clone git@github.com:gamman/stupid-F....
发表于 10-21 10:06 9次 阅读
嵌入式搭建ftp服务器

为什么嵌入式开发中一般都使用Linux系统?

Linux系统与其它操作系统相比具有轻量化、易裁剪、稳定性高、免费开源等优势,且Linux系统能很好....
发表于 10-21 09:51 6次 阅读
为什么嵌入式开发中一般都使用Linux系统?

LCD屏幕操作原理_嵌入式Linux

5.1 LCD 操作原理在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。....
发表于 10-21 09:51 8次 阅读
LCD屏幕操作原理_嵌入式Linux

嵌入式Linux怎么搭建开发环境?

全文下载地址:嵌入式Linux系统开发完全手册 第二版2.1 安装Windows软件2.1.1 这么....
发表于 10-21 09:36 7次 阅读
嵌入式Linux怎么搭建开发环境?

嵌入式开发版如何通过网线连接电脑,SecureCRT连接嵌入式板子

1.与开发版相连的网口修改为静态IP2.关闭电脑防火墙3.打开TFTP服务器创建工具,创建TFTP服....
发表于 10-21 09:36 6次 阅读
嵌入式开发版如何通过网线连接电脑,SecureCRT连接嵌入式板子

嵌入式Linux开发的流程是怎样的呢

单片机和Linux的区别在哪? 嵌入式Linux开发的流程是怎样的呢? ...
发表于 10-21 09:30 0次 阅读

嵌入式的初步了解

2020年2月25日,我第一次接触到了这门课程——嵌入式设计。在没有了解这门课之前,就连“嵌入式”这....
发表于 10-20 21:21 18次 阅读
嵌入式的初步了解

嵌入式 Linux 开发基本概念

1.2.1 嵌入式 Linux 开发有哪些内容?嵌入式 Linux 系统,就相当于一套完整的 PC ....
发表于 10-20 21:21 18次 阅读
嵌入式 Linux 开发基本概念

嵌入式 Linux 的学习新路线

很多人喜欢从系统启动流程开始学习:先学习裸机,裸机集合起来就是 u-boot,再学习内核移植、驱动开....
发表于 10-20 21:06 7次 阅读
嵌入式 Linux 的学习新路线

嵌入式系统开发者需要掌握什么技术?

大家好,我是小嵌,在知乎上看到这个问题,其中有一个答主的答案很经典,特此分享给大家。说实话,问题中嵌....
发表于 10-20 20:20 6次 阅读
嵌入式系统开发者需要掌握什么技术?

嵌入式Linux容器技术

嵌入式Linux容器技术一、Linux容器技术Linux Container容器是一种内核虚拟化技术....
发表于 10-20 20:06 8次 阅读
嵌入式Linux容器技术

嵌入式内存分布详解

前言硬件程序调试比较看重内存的分布情况,可以通过编译输出文件来分析运行时的数据结构如有疑问,欢迎指正....
发表于 10-20 20:06 8次 阅读
嵌入式内存分布详解

嵌入式Lua开发环境的搭建

背景作为一个嵌入式软件从业者,近几年的工作经历渐渐感觉到了从事嵌入式软件开发,工作投入高而产出低。提....
发表于 10-20 19:51 10次 阅读
嵌入式Lua开发环境的搭建

肝了半个月,我整理出了这篇嵌入式开发学习学习路线+知识点梳理)

不好意思久等了这篇文章让小伙伴们久等了。一年多以来,关于嵌入式开发学习路线、规划、看什么书等问题,被....
发表于 10-20 19:36 4次 阅读
肝了半个月,我整理出了这篇嵌入式开发学习学习路线+知识点梳理)

嵌入式LinuxQT操作自定义按键

嵌入式Linux系统中,用QT做的应用层程序,需要检测自定义的按键状态。使用的QT的按键事件,驱动层....
发表于 10-20 19:21 6次 阅读
嵌入式LinuxQT操作自定义按键

嵌入式常用的开源库

阅读目录linux/嵌入式常用开源库列表其他资料参考资料linux下/嵌入式常用的开源库名字及简介,....
发表于 10-20 19:20 8次 阅读
嵌入式常用的开源库

1-嵌入式Linux系统软件组成

1 Windows PC:BIOS——>(启动)windows内核——>(挂载硬盘)系统盘/应用盘—....
发表于 10-20 18:51 8次 阅读
1-嵌入式Linux系统软件组成

20分钟轻松搭建一个嵌入式web服务器

嵌入式Linux,boa,web服务器
发表于 10-20 18:50 9次 阅读
20分钟轻松搭建一个嵌入式web服务器

使用WSL搭建嵌入式开发环境

这里介绍使用WSL安装交叉编译环境
发表于 10-20 18:36 4次 阅读
使用WSL搭建嵌入式开发环境

嵌入式设备NFS挂载目录(基于iTop 4412)

嵌入式设备NFS挂载目录文章目录嵌入式设备NFS挂载目录1. 背景2. 工作量分析3. 上位机搭建N....
发表于 10-20 18:36 6次 阅读
嵌入式设备NFS挂载目录(基于iTop 4412)

分享一些嵌入式相关的开源项目

关注+星标公众号,不错过精彩内容来源 | 人人都是极客大家平时学习的资源可能来自不同地方,对于程序员....
发表于 10-20 18:35 7次 阅读
分享一些嵌入式相关的开源项目

嵌入式驱动工程师开发学习路线

ARM+LINUX路线,主攻嵌入式Linux操作系统及其上应用软件开发目标:(1)掌握主流嵌入式微处....
发表于 10-20 18:21 13次 阅读
嵌入式驱动工程师开发学习路线

【嵌入式】构建嵌入式Linux系统(uboot、内核、文件系统)

嵌入式Linux系统知识架构及层次嵌入式Linux系统构成及启动略析嵌入式Linux三剑客之uboo....
发表于 10-20 18:20 23次 阅读
【嵌入式】构建嵌入式Linux系统(uboot、内核、文件系统)

嵌入式行业是个坑吗?

在知乎上看到一篇写当下嵌入式行业的文章,感觉很接地气,想入行或者想了解嵌入式行业的可以看下:嵌入式就....
发表于 10-20 17:51 15次 阅读
嵌入式行业是个坑吗?

linux及嵌入式学习必备神器-树莓派4b

假期来了,想学习linux,学习嵌入式开发的小伙伴需要一款神器树莓派4b树莓派4b树莓派4b的核心处....
发表于 10-20 17:50 11次 阅读
linux及嵌入式学习必备神器-树莓派4b

初级嵌入式软件工程师学习路线(在校本科或者硕士)

ARM+LINUX路线,主攻嵌入式Linux操作系统及其上应用软件开发目标: (1)掌握主流嵌....
发表于 10-20 17:36 6次 阅读
初级嵌入式软件工程师学习路线(在校本科或者硕士)

如何学习嵌入式linux?学习嵌入式linux有什么技术门槛吗?

如何学习嵌入式linux?学习嵌入式linux有什么技术门槛吗?...
发表于 10-20 07:23 0次 阅读

怎样去移植通用嵌入式系统呢

怎样去移植通用嵌入式系统呢? Linux在嵌入式中有何应用? ...
发表于 10-20 06:57 0次 阅读

Linux软件系统的层次关系

1、Linux软件系统的层次关系 软件系统可分为:应用程序、库、操作系统(内核)、驱动程序 以点亮LED为例,分析各层间的...
发表于 10-19 17:17 101次 阅读

输入子系统的作用与框架

一、输入子系统的作用与框架 1、输入设备 按键、鼠标、触摸屏:gt811,ft56xx  有多个输入设备需要驱动的时候,假如不考虑输...
发表于 10-19 17:13 101次 阅读

驱动程序开发步骤

驱动程序开发步骤   编写一个驱动程序的大致流程如下: 1)查看原理图,数据手册,了解设备的操作方法; 2)在内核中找到相...
发表于 10-19 17:11 101次 阅读

AM4379 AM437x ARM Cortex-A9 微处理器 (MPU)

TI AM437x高性能处理器基于ARM Cortex-A9内核。 这些处理器通过3D图形加速得到增强,可实现丰富的图形用户界面,还配备了协处理器,用于进行确定性实时处理(包括EtherCAT,PROFIBUS,EnDat等工业通信协议)。该器件支持高级操作系统(HLOS)。基于Linux的® 可从TI免费获取。其它HLOS可从TI的设计网络和生态系统合作伙伴处获取。 这些器件支持对采用较低性能ARM内核的系统升级,并提供更新外设,包括QSPI-NOR和LPDDR2等存储器选项。 这些处理器包含功能方框图中显示的子系统,并且后跟相应的“说明”中添加了更多信息说明。 处理器子系统基于ARM Cortex-A9内核,PowerVR SGX™图形加速器子系统提供3D图形加速功能以支持显示和高级用户界面。 可编程实时单元子系统和工业通信子系统(PRU-ICSS与ARM内核分离,允许单独操作和计时,以实现更高的效率和灵活性.PRU-ICSS支持更多外设接口和EtherCAT,PROFINET,EtherNet /IP,PROFIBUS,以太网Powerlink,Sercos,EnDat等...
发表于 09-25 11:51 364次 阅读
AM4379 AM437x ARM Cortex-A9 微处理器 (MPU)