rockchip 使用编译前要注意以下设置
请注意使用一键编译命令之前需要设置环境变量,选择好自己需要编译的平台,举例:
source build/envsetup.sh
lunch rk3566_rgo-userdebug
============================================================
make installclean -j24;make -j24
rm rockdev/Image-tab10_rk66/*;./mkimage.sh;rm RKTools/linux/Linux_Pack_Firmware/rockdev/Image/*;cp rockdev/Image-tab10_rk66/* RKTools/linux/Linux_Pack_Firmware/rockdev/Image/

网络测试工具
ifconfig eth0 192.168.9.132 netmask 255.255.255.0
iperf -s -i 10
iperf -c 192.168.1.133 -t 50

/************display 调试相关命令************/
//通过打印当前显示帧率,判断播放是否异常
setprop debug.sf.fps 1
logcat -c ;logcat | grep mFps
//通过 SurfaceFlinger Services 检查合成策略是否正常
dumpsys SurfaceFlinger
//若不正常,通过打印 HWC log 查看不正常原因
adb shell "setprop sys.hwc.log 511"
adb shell "logcat -c ;logcat" > hwc.log
/*****************************************/

cat /sys/fs/pstore/console-ramoops-0  
打印出上次系统复位前的设备信息。若出现拷机异常或者异常掉电的情况,可通过该命令打印出上一次系统运行状态的日志

/****************调试  反汇编命令************/
Crash 日志
我们通过构造该错误,在 HWC 代码适当位置加上如下代码:
struct test_t{
int a = 0;
int b = 0;
int c = 0;
void add(){return;};
};
struct test_t *test_a;
//构造 test_a
test_a = NULL;
//设置为 NULL
test_a->c = 1;
//访问 NULL 指针的成员

通过 addr2line 命令可反编译到现场出错位置:  //000000000004195c  Crash 首地址
addr2line -e $OUT/symbols/system/lib64/hw/hwcomposer.rk30board.so 000000000004195c
可得到出错地址

我们进一步分析问题,通过以下命令可以反汇编,将对应汇编源码输出:
prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-objdu
mp -S -D $OUTsymbols/system/lib64/hw/hwcomposer.rk30board.so > hwcomposer.dump
在输出文件 hwcomposer.dump 查询 4195c 堆栈打印地址位置

/****************************自旋锁***********************/
接口API的类型    spinlock中的定义    raw_spinlock的定义
定义spin lock并初始化    DEFINE_SPINLOCK    DEFINE_RAW_SPINLOCK
动态初始化spin lock    spin_lock_init    raw_spin_lock_init
获取指定的spin lock    spin_lock    raw_spin_lock
获取指定的spin lock同时disable本CPU中断    spin_lock_irq    raw_spin_lock_irq
保存本CPU当前的irq状态,disable本CPU中断并获取指定的spin lock    spin_lock_irqsave    raw_spin_lock_irqsave
获取指定的spin lock同时disable本CPU的bottom half    spin_lock_bh    raw_spin_lock_bh
释放指定的spin lock    spin_unlock    raw_spin_unlock
释放指定的spin lock同时enable本CPU中断    spin_unlock_irq    raw_spin_unock_irq
释放指定的spin lock同时恢复本CPU的中断状态    spin_unlock_irqstore    raw_spin_unlock_irqstore
获取指定的spin lock同时enable本CPU的bottom half    spin_unlock_bh    raw_spin_unlock_bh
尝试去获取spin lock,如果失败,不会spin,而是返回非零值    spin_trylock    raw_spin_trylock
判断spin lock是否是locked,如果其他的thread已经获取了该lock,那么返回非零值,否则返回0    spin_is_locked    raw_spin_is_locked
************************************************************

/***********************休眠前将log信息打出*****************************/
echo N >sys/module/printk/parameters/console_suspend

/***********************************************************************/

grep -nr rockchip_suspend |grep ipc  搜索

/************************oops分析************************/

在内核开发的过程中,经常会碰到内核崩溃,比如空指针异常,内存访问越界。通常我们只能靠崩溃之后打印出的异常调用栈信息来定位crash的位置和原因。总结下分析的方法和步骤。

通常oops发生之后,会在串口控制台或者dmesg日志输出看到如下的log,以某arm下linux内核的崩溃为例,

<2>[515753.310000] kernel BUG at net/core/skbuff.c:1846!
<1>[515753.310000] Unable to handle kernel NULL pointer dereference at virtual address 00000000
<1>[515753.320000] pgd = c0004000
<1>[515753.320000] [00000000] *pgd=00000000
<0>[515753.330000] Internal error: Oops: 817 [#1] PREEMPT SMP
<0>[515753.330000] last sysfs file: /sys/class/net/eth0.2/speed
<4>[515753.330000] module:  http_timeout     bf098000    4142
...
<4>[515753.330000] CPU: 0    Tainted: P             (2.6.36 #2)
<4>[515753.330000] PC is at __bug+0x20/0x28
<4>[515753.330000] LR is at __bug+0x1c/0x28
<4>[515753.330000] pc : [<c01472d0>]    lr : [<c01472cc>]    psr: 60000113
<4>[515753.330000] sp : c0593e20  ip : c0593d70  fp : cf1b5ba0
<4>[515753.330000] r10: 00000014  r9 : 4adec78d  r8 : 00000006
<4>[515753.330000] r7 : 00000000  r6 : 0000003a  r5 : 0000003a  r4 : 00000060
<4>[515753.330000] r3 : 00000000  r2 : 00000204  r1 : 00000001  r0 : 0000003c
<4>[515753.330000] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
<4>[515753.330000] Control: 10c53c7d  Table: 4fb5004a  DAC: 00000017
<0>[515753.330000] Process swapper (pid: 0, stack limit = 0xc0592270)
<0>[515753.330000] Stack: (0xc0593e20 to 0xc0594000)
<0>[515753.330000] 3e20: ce2ce900 c0543cf4 00000000 ceb4c400 000010cc c8f9b5d8 00000000 00000000
<0>[515753.330000] 3e40: 00000001 cd469200 c8f9b5d8 00000000 ce2ce8bc 00000006 00000026 00000010
...
<4>[515753.330000] [<c01472d0>] (PC is at __bug+0x20/0x28)
<4>[515753.330000] [<c01472d0>] (__bug+0x20/0x28) from [<c0543cf4>] (skb_checksum+0x3f8/0x400)
<4>[515753.330000] [<c0543cf4>] (skb_checksum+0x3f8/0x400) from [<bf11a8f8>] (et_isr+0x2b4/0x3dc [et])
<4>[515753.330000] [<bf11a8f8>] (et_isr+0x2b4/0x3dc [et]) from [<bf11aa44>] (et_txq_work+0x24/0x54 [et])
<4>[515753.330000] [<bf11aa44>] (et_txq_work+0x24/0x54 [et]) from [<bf11aa88>] (et_tx_tasklet+0x14/0x298 [et])
<4>[515753.330000] [<bf11aa88>] (et_tx_tasklet+0x14/0x298 [et]) from [<c0171510>] (tasklet_action+0x12c/0x174)
<4>[515753.330000] [<c0171510>] (tasklet_action+0x12c/0x174) from [<c05502b4>] (__do_softirq+0xfc/0x1a4)
<4>[515753.330000] [<c05502b4>] (__do_softirq+0xfc/0x1a4) from [<c0171c98>] (irq_exit+0x60/0x64)
<4>[515753.330000] [<c0171c98>] (irq_exit+0x60/0x64) from [<c01431fc>] (do_local_timer+0x60/0x74)
<4>[515753.330000] [<c01431fc>] (do_local_timer+0x60/0x74) from [<c054f900>] (__irq_svc+0x60/0x10c)
<4>[515753.330000] Exception stack(0xc0593f68 to 0xc0593fb0)

在这里,我们着重关注下面几点:

Oops信息 kernel BUG at net/core/skbuff.c:1846! Unable to handle kernel NULL pointer dereference at virtual address 00000000 , 这里能够简要的告诉是什么问题触发了oops,如果是由代码直接调用BUG()/BUG_ON()一类的,还能给出源代码中触发的行号。

寄存器PC/LR的值 PC is at __bug+0x20/0x28 LR is at __bug+0x1c/0x28 , 这里PC是发送oops的指令, 可以通过LR找到函数的调用者

CPU编号和CPU寄存器的值 sp ip fp r0~r10 ,

oops时,应用层的Process Process swapper (pid: 0, stack limit = 0xc0592270) , 如果crash发生在内核调用上下文,这个可以用来定位对应的用户态进程

最重要的是调用栈,可以通过调用栈来分析错误位置

这里需要说明一点, skb_checksum+0x3f8/0x400 ,在反汇编后,可以通过找到skb_checksum函数入口地址偏移0x3f8来精确定位执行点

在需要精确定位出错位置的时候,我们就需要用到反汇编工具objdump了。下面就是一个示例,

objdump -D -S xxx.o > xxx.txt

举个例子,比如我们需要寻找栈 (et_isr+0x2b4/0x3dc [et]) from [<bf11aa44>] (et_txq_work+0x24/0x54 [et]) ,这里我们可以知道这个函数是在 [et] 这个obj文件中,那么我们可以直接去找 et.o ,然后反汇编 objdump -D -S et.o > et.txt , 然后et.txt中就是反汇编后的指令。当然,单看汇编指令会非常让人头疼,我们需要反汇编指令和源码的一一对应才好分析问题。这就需要我们在编译compile的时候加上 -g 参数,把编译过程中的symbol和调试信息一并加入到最后obj文件中,这样objdump反汇编之后的文件中就包含嵌入的源码文件了。

对于内核编译来讲,就是需要在内核编译的根目录下,修改Makefile中 KBUILD_CFLAGS , 加上 -g 编译选项。

KBUILD_CFLAGS   := -g -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \                       
               -fno-strict-aliasing -fno-common \
               -Werror-implicit-function-declaration \
               -Wno-format-security \
               -fno-delete-null-pointer-checks -Wno-implicit-function-declaration \
               -Wno-unused-but-set-variable \
               -Wno-unused-local-typedefs

下面是一份反编译完成后的文件的部分截取。我们可以看到,这里0x1f0是 <et_isr> 这个函数的入口entry,c的源代码是在前面,后面跟的汇编代码是对应的反汇编指令

f0 <et_isr>:
et_isr(int irq, void *dev_id)
#else
static irqreturn_t BCMFASTPATH
et_isr(int irq, void *dev_id, struct pt_regs *ptregs)
#endif
{
f0:   e92d40f8    push    {r3, r4, r5, r6, r7, lr}
f4:   e1a04001    mov r4, r1
    struct chops *chops;
    void *ch;
    uint events = 0;

et = (et_info_t *)dev_id;
    chops = et->etc->chops;
f8:   e5913000    ldr r3, [r1]
    ch = et->etc->ch;

/* guard against shared interrupts */
    if (!et->etc->up)
fc:   e5d32028    ldrb    r2, [r3, #40]   ; 0x28
    struct chops *chops;
    void *ch;
    uint events = 0;

et = (et_info_t *)dev_id;
    chops = et->etc->chops;
:   e5936078    ldr r6, [r3, #120]  ; 0x78
    ch = et->etc->ch;
:   e593507c    ldr r5, [r3, #124]  ; 0x7c

/* guard against shared interrupts */
    if (!et->etc->up)
:   e3520000    cmp r2, #0
c:   1a000001    bne 218 <et_isr+0x28>
:   e1a00002    mov r0, r2
:   e8bd80f8    pop {r3, r4, r5, r6, r7, pc}
        goto done;

/* get interrupt condition bits */
    events = (*chops->getintrevents)(ch, TRUE);
:   e5963028    ldr r3, [r6, #40]   ; 0x28
c:   e1a00005    mov r0, r5
:   e3a01001    mov r1, #1
:   e12fff33    blx r3
:   e1a07000    mov r7, r0

/* not for us */
    if (!(events & INTR_NEW))
c:   e2100010    ands    r0, r0, #16
:   08bd80f8    popeq   {r3, r4, r5, r6, r7, pc}

ET_TRACE(("et%d: et_isr: events 0x%x\n", et->etc->unit, events));
    ET_LOG("et%d: et_isr: events 0x%x", et->etc->unit, events);

/* disable interrupts */
    (*chops->intrsoff)(ch);
:   e5963038    ldr r3, [r6, #56]   ; 0x38
:   e1a00005    mov r0, r5
c:   e12fff33    blx r3
        (*chops->intrson)(ch);
    }

在objdump反汇编出指令之后,我们可以根据调用栈上的入口偏移来找到对应的精确调用点。例如, (et_isr+0x2b4/0x3dc [et]) from [<bf11aa44>] (et_txq_work+0x24/0x54 [et]) , 我们可以知道调用点在 et_isr入口位置+0x2b4偏移 ,而刚才我们看到 et_isr的入口位置是0x1f0 ,那就是说在 0x1f0+0x2b4=0x4a4 偏移位置。我们来看看,如下指令 4a4: e585007c str r0, [r5, #124] ; 0x7c ,其对应的源代码就是上面那一段c代码, skb->csum = skb_checksum(skb, thoff, skb->len - thoff, 0); 。而我们也知道,下一个调用函数的确是 skb_checksum , 说明精确的调用指令是准确的。

ASSERT((prot == IP_PROT_TCP) || (prot == IP_PROT_UDP));
        check = (uint16 *)(th + ((prot == IP_PROT_UDP) ?
c:   e3580011    cmp r8, #17
:   13a0a010    movne   sl, #16
:   03a0a006    moveq   sl, #6
            offsetof(struct udphdr, check) : offsetof(struct tcphdr, check)));
        *check = 0;
:   e18720ba    strh    r2, [r7, sl]
    thoff = (th - skb->data);
    if (eth_type == HTON16(ETHER_TYPE_IP)) {
        struct iphdr *ih = ip_hdr(skb);
        prot = ih->protocol;
        ASSERT((prot == IP_PROT_TCP) || (prot == IP_PROT_UDP));
        check = (uint16 *)(th + ((prot == IP_PROT_UDP) ?
c:   e087200a    add r2, r7, sl
:   e58d2014    str r2, [sp, #20]
            offsetof(struct udphdr, check) : offsetof(struct tcphdr, check)));
        *check = 0;
        ET_TRACE(("et%d: skb_checksum: \n", et->etc->unit));
        skb->csum = skb_checksum(skb, thoff, skb->len - thoff, 0);
:   e5952070    ldr r2, [r5, #112]  ; 0x70
:   e58dc008    str ip, [sp, #8]
c:   e0612002    rsb r2, r1, r2
a0:   ebfffffe    bl  0 <skb_checksum>
a4:   e585007c    str r0, [r5, #124]  ; 0x7c
        *check = csum_tcpudp_magic(ih->saddr, ih->daddr,
a8:   e5953070    ldr r3, [r5, #112]  ; 0x70

static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
           unsigned short proto, __wsum sum)
{     
    __asm__(
ac:   e59dc008    ldr ip, [sp, #8]

有几点比较geek的地方需要注意:

函数调用栈的调用不一定准确(不知道why?可能因为调用过程是通过LR来反推到的,LR在执行过程中有可能被修改?),但是有一点可以确认,调用的点是准确的,也就是说调用函数不一定准,但是调用函数+偏移是能够找到准确的调入指令
inline的函数以及被优化的函数可能不会出现在调用栈上,在编译的时候因为优化的需要,会就地展开代码,这样就不会在这里有调用栈帧(stack frame)存在了
/*************************oops  end*******************************/
1.Linux 内核相关的延时
延时分为忙延时和休眠延时。而忙延时是运用在等待时间极短的场合,而进程和中断都可以使用忙延时。而休眠延时是应用到等待时间较长的场合,只能于进程不能够用在中断中。
而如果需要进程能够随时随地的进行休眠唤醒,这必须采用Linux内核的等待队列机制,这一般运用在不需要一直工作的外设中,且一般是为了降低功率消耗,一般运用在sensor中比较常见。而本身信号量能够使进程休眠本身也是基于其等待队列实现的。

2.在rockchip 中遇到的引脚不可控制的问题;
在设备树里配置正常,且驱动无报错,无引脚复用的情况,且系统中相应的设备节点也有,但通过echo  和cat 命令查看软件的状态一直是为0,为低的状态,但从硬件引脚表现来看,其引脚的电压一直是低电平,即电压为0,利用echo 通过设备节点来设置电压为高电平时,日志无报错,但软件cat 查看其节点值一直保持为0,即电压为0的状态。后面才发现,在dts 配置引脚的时候,需要将引脚设置为:默认状态,即:pinctrl-names = "default"; (有些引脚不用使之为default 的状态,因为其默认就为default gpio 的引脚功能,所以不加该配置也是可控制的,这不可控制,其实是GPIO处于其它的功能,只是我们不知道它目前是处于什么功能)否则会出现引脚不可控的情况出现。

3.TPL(Tiny Program Loader)和 SPL(Secondary Program Loader)是比 U-Boot 更早阶段的 Loader:
TPL:运行在 sram 中,负责完成 ddr 初始化;
SPL:运行在 ddr 中,负责完成系统的 lowlevel 初始化、后级固件加载(trust.img 和 uboot.img);
U-Boot proper:运行在ddr中,即我们通常所说的"U-Boot",它负责引导kernel;
说明:U-Boot proper 而这一说法主要是为了和 SPL 区分开。而U-Boot proper 我们都简称为 U-Boot。

4.虚拟内存的哪个页面映射到物理内存的哪个页帧是通过页表(Page Table)来描述的,页表保存在物理内存中,MMU会查找页表来确定一个VA(虚拟地址)应该映射到什么PA(物理地址)。而在启用MMU时,在我们程序中使用的地址均为虚拟内存地址,而这些都会引发MMU进行查表和地址转换操作。变换后的虚拟地址(MVA,modified virtrual address)
段错误在程序中有时会导致进程崩溃的情况,而它是这样产生的:
(1)当用户程序要访问的一个VA,经MMU检查无权访问。
(2)MMU产生一个异常,CPU从用户模式切换到特权模式,跳转到内核代码中执行异常服务程序。
(3)内核把这个异常解释为段错误,把引发异常的进程终止掉。
5.内核中的延迟工作delayed_work,其本质也是通过工作队列与定时器实现。 Linux 的中断处理分为两半部,顶半部处理紧急的硬件操作,底半部处理不紧急的耗时操作,而tasklet 和工作队列都是调度中断底半部的良好的机制,且tasklet 是基于软中断实现,内核定时器也依靠软中断来实现的。

/******************生成 .so 库的命令*********************/
 gcc -fPIC -shared dl.c -o libdl.so

dl.c 文件名  libdl.so 要生成的库名  在android 中一般是通过在 android.mk 中去生成编译.so 文件。

在将其opendl.c 编译为可执行文件
 gcc -rdynamic -o opendl opendl.c -ldl
 
 c语言为了使程序方便扩展,具备通用性,可以采用插件形式。采用异步事件驱动模型,保证主程序逻辑不变,将各个业务已动态链接库的形式加载进来,这就是所谓的插件。linux提供了加载和处理动态链接库的系统调用,非常方便。
c语言提供api让我们加载动态链接库文件 android 即上的.so文件

dlopen函数以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()的调用进程
dlclose 卸载打开的库
dlerror 返回出现的错误
dlsym dlsym通过句柄和连接符名称获取函数名或者变量名

/******************************************************/

rockchip rk3566 调试杂记相关推荐

  1. Rockchip RK3566、RK3588、RV1109系统芯片详细参数介绍

    去年,Rockchip在中国举办了一场演讲,他们在演讲中强调了他们的2020年处理器路线图,我们还了解了Rockhip RK3588 Cortex-A76/A55.RK3530 Cortex-A55 ...

  2. RK3566调试GC2053

    电路 RK3566主板外接了一个MIPI接口涉嫌头模组,I2C接口I2C2,模组Sensor为GC2053,模组的设备地址为0x37(地址需和模组厂家确定),电路如下: 管脚连接关系如下: GPIO0 ...

  3. rockchip rk3566 android11 网口log报错: DMA engine initialization failed

    问题描述:上电初始化前将网口插入,然后上电初始化网口能够正常使用,且能够找到PHY,ifconfig 查看能够有eth0 产生,网口正常使用且能够热插拔,但上电初始化时,不插入网口,就会报DMA en ...

  4. RK3566调试VL53L01

    一.添加.编译驱动 1.从ST官方下载en.STSW-IMG005软件包,当前最新为1.0.4版本,软件包中有LinuxDriverMassMarket_1.0.7文件夹,继续打开LinuxDrive ...

  5. RK3568驱动OV13850摄像头模组调试过程

    摄像头介绍 品牌:Omnivision 型号:CMK-OV13850 接口:MIPI 像素:1320W OV13850彩色图像传感器是一款低电压.高性能1/3.06英寸1320万像素CMOS图像传感器 ...

  6. 瑞芯微RK3566 简单介绍与Android11.0 固件编译

    rockchip RK3566 瑞芯微 RK3566 四核 64 位Cortex-A55 处 理 器 , 主 频 最 高1.8GHz,效能有大幅提升:采用22nm先进工艺,具有低功耗高性能的特点. 瑞 ...

  7. 瑞芯微电子RockChip(RK3588)

    瑞芯微电子RockChip 1.RK3588 RK3566 RK3530 2.详细介绍一下RK3566.RK3588.RV1109: 1.RK3588 RK3566 RK3530 RK3588 RK3 ...

  8. rk3568 添加gc2053摄像头驱动

    在设备树文件代码中添加 gc2053 设备节点 &i2c2 { status = "okay"; pinctrl-0 = <&i2c2m1_xfer>; ...

  9. 【待更新】【UWB】UWB 学习、使用及 QCA平台移植实例

    文章目录 ENV 开发环境 运行环境 UWB技术概述 百度百科 个人总结 应用场景(实例待补充) 相关厂商 原厂 QCA平台移植实例 环境搭建 软件开发 编译调试 调试杂记 要点难点 使用概述 附录 ...

  10. 转载:看一遍就理解,图解单链表反转

    转载:看一遍就理解,图解单链表反转 看一遍就理解,图解单链表反转 前言 反转链表是程序员必备的基本素养,经常在面试.笔试的过程中出现.一直觉得反转链表实现代码不是很好理解,决定搬leetcode那道经 ...

最新文章

  1. BGA封装芯片手工焊接攻略
  2. 华为CodeCraft2017算法结果检查工具(包含测试用例展示)
  3. 【AudioVideo】视频媒体会话回调(11)
  4. cocos2d-x游戏开发系列教程-坦克大战游戏之坦克的显示
  5. 黑马lavarel教程---9、缓存操作
  6. 苹果android投屏,iPhone手机如何投屏到智能电视?
  7. 聊聊高并发(三十三)Java内存模型那些事(一)从一致性(Consistency)的角度理解Java内存模型
  8. 随时随地能写代码, vscode.dev 出手了
  9. php软件开发--公众平台
  10. Maven服务器的使用之Maven桌面项目和Maven Web项目的创建
  11. 论文笔记_S2D.14-2014-NIPS_利用多尺度深度网络从单张图像预测深度图
  12. VS2015之博大精深的MFC项目开发(一)
  13. Latex 公式速查
  14. 宝马冷却系统及电动冷却液泵部件(电子水泵)功能特性及标准
  15. 私网ip和公网ip_详解
  16. Serialization assertion safeVersionRead == safeSerializationVersion failed.
  17. JavaScript 透明背景色
  18. 英华特在创业板提交注册:拟募资约5亿元,股权结构较为分散
  19. html中如何定义斜框,html表格单元格添加斜下框线的方法
  20. nn.Linear()函数详解

热门文章

  1. cmd 控制台 提示:请求的操作需要提升!
  2. 黑之契约者OP《Howling》完整版歌词
  3. FLAGS 作用及用法
  4. 移动智能终端之应用商店和应用的安全管理机制(笔记四)
  5. 【Vic的小课堂】Unity实现游戏功能(1)—矩形框选
  6. cocos creator3.x 触控方向键实现
  7. 万年历带日程提醒功能
  8. 高考数学必考知识点高中数学重点知识归纳
  9. arcmap武汉市各个行政区域的森林覆盖率和水体覆盖率
  10. 黑龙江计算机比赛,信息工程学院在第十三届中国大学生计算机设计大赛黑龙江省赛中喜获佳绩...