arm linux debug notes (error note)

来源:互联网 发布:网络运维服务承诺书 编辑:程序博客网 时间:2024/05/21 04:43

1.  forgot __func__ and pointer is judged too earlily.

ret = sprdfb_panel_constructor(pan_node, fb_dev);if (ret) {pr_err("%s: failed to construct panel device\n"); // lose __func__return -EFAULT;}

%s, __func__, forgot __func__

if (!fb_dev || fb_dev->panel)return -ENODEV; // Actually, panel pointer is NULL...pan_node = sprdfb_panel_search(fb_dev);if (!pan_node) {pr_warn("can't find panel specified by cmdline, try reading id\n");}ret = sprdfb_panel_constructor(pan_node, fb_dev);if (ret) {pr_err("%s: failed to construct panel device\n", __func__);return -EFAULT;}panel = fb_dev->panel;

The error log is as following:

7sprdfb_panel: ---- enter: sprdfb_panel_device_register ----1Unable to handle kernel paging request at virtual address 600001131pgd = c00040001[60000113] *pgd=000000000Internal error: Oops: 5 [#1] PREEMPT SMP ARMdModules linked in:dCPU: 1 PID: 1 Comm: swapper/0 Tainted: G        W    3.10.17-00026-g6d61c92-dirty #29dtask: d7098000 ti: d70a0000 task.ti: d70a0000PC is at strnlen+0x1c/0x30LR is at string.isra.3+0x34/0xc8pc : [<c01e5e20>]    lr : [<c01e6e34>]    psr: 20000193 // stopped at printk, actually is pr_err.sp : d70a1c78  ip : 00000020  fp : d70a1d58r10: c055827b  r9 : c084b0e0  r8 : 00000000r7 : 60000113  r6 : ffffffff  r5 : c084b0e0  r4 : c084ad0ar3 : 60000113  r2 : 60000113  r1 : 60000112  r0 : 60000113 // 6000113 is a abnormal address!!!Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernelControl: 10c53c7d  Table: 8000406a  DAC: 00000015

2.  pointer should not NULL

porch = kzalloc(sizeof(struct timing_rgb), GFP_KERNEL);panel = kzalloc(sizeof(struct panel_spec), GFP_KERNEL);if (!panel || porch) // judge porch not right, should !porchgoto alloc_panel_mem_error;

3. The field name doesn't not match

name = (char *)of_get_property(pan_node,"sprdfb,dispc-dsi-panel-name", NULL);if (!name) {strlcpy(panel->panel_name, "unspecified", PANEL_NAME_LEN);ret = -ENXIO;pr_err("%s:%d, Panel name not specified\n",__func__, __LINE__);goto parse_dt_error;} else {strlcpy(panel->panel_name, name, PANEL_NAME_LEN);pr_info("%s: Panel: %s is specified\n",__func__, panel->panel_name);}

The name in dtsi is "dispc-panel-name", but in source code, the name is "dispc-dsi-panel-name".

4. NULL Pointer

static int sprdfb_panel_parse_dcs_cmds(const struct device_node *np,struct dsi_cmds_list *pcmds, char *cmd_key){const char *data;int dt_len = 0, len;char *buf, *bp;struct dsi_cmd_desc *d;int cnt = 0;pr_debug("---- enter: %s ----\n", __func__);data = of_get_property(np, cmd_key, &dt_len);if (!data) {pr_err("%s: failed, key=%s\n", __func__, cmd_key);return -ENOMEM;}buf = kzalloc(sizeof(char) * dt_len, GFP_KERNEL);if (!buf)return -ENOMEM;memcpy(buf, data, dt_len);/* scan dcs commands */bp = buf;len = dt_len;d = (struct dsi_cmd_desc *)bp;d->c_len = ntohs(d->c_len); // If d is NULL, now dereference it, kernel will be dumped. while (len > (sizeof(*d) + d->c_len)) {if (d->c_len > len) {pr_err("%s: dtsi cmd=%x error, len=%d",__func__, d->data_type, d->c_len);goto exit_free;}pr_debug("data type is %d, cmd len is %d\n",d->data_type, d->c_len);bp += sizeof(*d) + d->c_len;len -= sizeof(*d) + d->c_len;d = (struct dsi_cmd_desc *)bp;d->c_len = ntohs(d->c_len);cnt++;}pcmds->cmds_cnt = cnt;pcmds->cmds = (struct dsi_cmd_desc *)buf;return 0;exit_free:kfree(buf);return -EFAULT;}


5. Init sequence for using dts

1) platform_bus_init 

2) iomap

3) register all platform_driver to platform_driver bus

4) hwspinlock init
   4.1 find the hwspinlock node in DTS
   4.2 register the hwspinlock device to platform_device bus
   4.3 hwspinlock probe() and init the hwspinlock data struct
   4.4 early_init_hwspinlock

5) ADI_init and ADC_init

6) populate the DT, register all devices to platform_device bus

 

6. name is defined wrongly

data = (char *)of_get_property(node,"sprdfb,dispc-dsi-color-mode-polarity", NULL);if (data) {if (!strcmp(data, "negative"))panel->info.mipi->color_mode_pol = SPRDFB_POLARITY_NEG;elsepanel->info.mipi->color_mode_pol = SPRDFB_POLARITY_POS;} elsepanel->info.mipi->color_mode_pol = SPRDFB_POLARITY_POS;

The field "sprdfb,dispc-dsi-color-mode-polarity" is right, but previously, it is wrong, "-polarity" is missed.
In dtsi, the field is as following:
sprdfb,dispc-dsi-h-sync-polarity = "positive";sprdfb,dispc-dsi-v-sync-polarity = "positive";sprdfb,dispc-dsi-de-polarity = "positive";sprdfb,dispc-dsi-te-polarity = "positive";sprdfb,dispc-dsi-color-mode-polarity = "negative";sprdfb,dispc-dsi-shut-down-polarity = "negative";

7. pointer to pointers and dsi commands

static int sprdfb_dsi_tx_cmds(struct panel_spec *panel,struct dsi_cmd_desc **cmds, u32 cmds_len, bool force_lp){int i, time, len;struct ops_mipi *ops = panel->info.mipi->ops;u8 *data;u16 work_mode = panel->info.mipi->work_mode;pr_info("%s, len: %d\n", __func__, cmds_len);if (!ops->mipi_set_cmd_mode ||!ops->mipi_dcs_write ||!ops->mipi_set_hs_mode ||!ops->mipi_set_lp_mode ||!ops->mipi_force_write) {pr_err("%s: Expected functions are NULL.\n", __func__);return -EFAULT;}if (force_lp) {if (work_mode == SPRDFB_MIPI_MODE_CMD)ops->mipi_set_lp_mode();elseops->mipi_set_data_lp_mode();}ops->mipi_set_cmd_mode();for (i = 0; i < cmds_len; i++) {if (cmds[i]->data_type != DCS_SHORT_WRITE_0 &&cmds[i]->data_type != DCS_SHORT_WRITE_1) {len = cmds[i]->c_len + sizeof(cmds[i]->c_len);data = cmds[i]->payload - sizeof(cmds[i]->c_len);} else {len = cmds[i]->c_len;data = cmds[i]->payload;}pr_debug("dsi write cmd type: %d, len: %d\n",cmds[i]->data_type, len);if (cmds[i]->data_type == GENERIC_LONG_WRITE)ops->mipi_force_write(GENERIC_LONG_WRITE, data, len);elseops->mipi_dcs_write(data, len);if (cmds[i]->wait_time) {time = cmds[i]->wait_time * 1000;usleep_range(time, time);}}if (force_lp) {if (work_mode == SPRDFB_MIPI_MODE_CMD)ops->mipi_set_hs_mode();elseops->mipi_set_data_hs_mode();}return 0;}

struct dsi_cmds_list {struct dsi_cmd_desc *cmds[PANEL_MAX_CMDS_LEN];u32 cmds_cnt;};

struct dsi_cmd_desc {u8 data_type; /* BYTE[0] */u8 reserved; /* BYTE[1]: reserved */u8 wait_time; /* BYTE[2] */u16 c_len; /* BYTE[3...4]: cmd lenght */u8 payload[0]; /* BYTE[5] */} __packed;

/* 05: DCS short Wr; 39: DCS long Wr; 06: DCS read; 15: DCS short Wr */#define GENERIC_SHORT_WRITE_00x03#define GENERIC_SHORT_WRITE_10x13#define GENERIC_SHORT_WRITE_20x23#define GENERIC_LONG_WRITE0x29#define DCS_SHORT_WRITE_00x05#define DCS_SHORT_WRITE_10x15#define DCS_LONG_WRITE0x39#define GENERIC_SHORT_READ_00x04#define GENERIC_SHORT_READ_10x14#define GENERIC_SHORT_READ_20x24#define DCS_READ_00x06#define SET_MAX_RET_PKT_SIZE0x37

Parsing and handling commands of dsi are not easy. They should be paid a lot of attention to.
static int sprdfb_panel_parse_dcs_cmds(const struct device_node *np,struct dsi_cmds_list *pcmds, char *cmd_key){const char *data;int dt_len = 0, len, header;char *buf, *bp;int cnt = 0;pr_debug("---- enter: %s ----\n", __func__);data = of_get_property(np, cmd_key, &dt_len);if (!data) {pr_err("%s: failed, key=%s\n", __func__, cmd_key);return -ENOMEM;}buf = kzalloc(sizeof(char) * dt_len, GFP_KERNEL);if (!buf)return -ENOMEM;memcpy(buf, data, dt_len);/* scan dcs commands */bp = buf;len = dt_len;header = sizeof(struct dsi_cmd_desc);while (len > header) {pcmds->cmds[cnt] = (struct dsi_cmd_desc *)bp;pcmds->cmds[cnt]->c_len = ntohs(pcmds->cmds[cnt]->c_len);if (pcmds->cmds[cnt]->c_len > len) {pr_err("%s: data type is 0x%x error, len=%d\n",__func__, pcmds->cmds[cnt]->data_type,pcmds->cmds[cnt]->c_len);goto exit_free;}pr_debug("data type is 0x%x, cmd len is %d, remaining(%d), ""cnt(%d)\n", pcmds->cmds[cnt]->data_type,pcmds->cmds[cnt]->c_len, len, cnt + 1);bp += header;len -= header;bp += pcmds->cmds[cnt]->c_len;len -= pcmds->cmds[cnt]->c_len;cnt++;}pcmds->cmds_cnt = cnt;return 0;exit_free:kfree(buf);return -EFAULT;}

6. virtual address and physical address switch

trace32 -> CPU -> peripheral -> System Control and Config -> SCTLR_EL1 -> M -> enable (enable virtual address) / disable (physical address)

7 linux flags

__attribute__
        __attribute__(section),用来修饰函数时,可以使你把代码放在image的不同段,如:
                    void   f(void)   __attribute__((section(“new_section”)));
函数f()将被放到只读new_section段中,而不是.text中。
        __attribute((regparm(0))),表示不从寄存器中传递参数,如果是regparm(3)则调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从寄存器取参数。gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器,缺省使用寄存器,假如想通过堆栈传递,定义的c函数时要在函数前加上宏asmlinkage
       
asmlinkage
        在看内核源代码start_kernel函数时,第一个遇到的疑问是asmlinkage,原来asmlinkage是一个宏,它定义在文件include/asm-i386/linkage.h中,具体如下:
        #define
        asmlinkage CPP_ASMLINKAGE
        __attribute__((regparm(0))),其中CPP_ASMLINKAGE也是一个宏,定义在include/linux/linkage.h头文件中,具体为:      
        #define   CPP_ASMLINKAGE extern "C",
        extern “C”是用来实现C++和C的混合编程,而__attribute__是关键字,是gcc的C语言扩展,它可以设置函数属性(Function  Attribute)、变量属性(Variable  Attribute)和类型属性(Type  Attribute),总的来说,asmlinkage是个宏,使用它是为了保持参数在stack中,因为从汇编语言到C语言代码参数的传递是通过stack的,它也可能从stack中得到一些不需要的参数,asmlinkage将要解析那些参数。
       
__init
是一个宏定义,定义在arch/um/include/init.h文件中,具体如:
        #define   __init  __attribute__ ((__section__ (".init.text")))                
        这个标志符和函数声明放在一起,它表示gcc编译器在编译的时候需要把这个函数放在.init.text中,而这个section在内核完成初始化之后会被释放掉。
       
__weak
是一个宏定义,定义在include/asm-mips/linkage.h文件中,具体如:
        #define  __weak __attribute__((weak)),它常用于函数和变量的声明和函数的定义,
        是GNU compiler的扩展,被ARM  compiler支持,可以将一个函数声明为weak,
        当没有其他同名函数声明时调用weak,有其他同名函数时调用其他同名函数。
       
__va(x)        
是个宏,定义在include/asm-alpha/page.h文件中,具体如下:
        #define __va(x)  ((void *)((unsigned long)(x) + PAGE_OFFSET))

__pa(x)       
也是个宏,定义在include/asm-alpha/page.h文件中,具体如下:
        #define __pa(x) ((unsigned  long)(x)-PAGE_OFFSET),
其中的PAGE_OFFSET定义为0xffff800000000000UL或0xfffffc0000000000UL
       
register
可以用来修饰变量,表示寄存器变量,只能用于整型和字符变量,表示变量被存储在CPU的寄存器中, 而不像普通变量被存储在内存中,这样可以提高运算速度,它常用于在同一变量名频繁出现的地方,且 它只适用于局部变量和函数的形式参数,它属于auto型变量,不能作为全局变量
       
EXPORT_SYMBOL
      若内核函数或变量要被内核模块调用,则必须使用EXPORT_SYMBOL宏进行处理,作用之一是将该符        号连接到二进制文件的各个__ksymtab_xx_xx section,内核加载模块时,会先确认该模块调用的各内         核函数是否已export,也就是说EXPORT_SYMBOL可以将一个函数或变量以符号的方式导出给其他模块使用。

0 0
原创粉丝点击