When Linux kernel panic, what can we do ?

来源:互联网 发布:oa免费办公软件 编辑:程序博客网 时间:2024/06/06 13:22
注意: 版权所有, 转载请注明出处.

Caution: All rights reserved, Please indicate the source if reproduce.


Hardware: Freescale iMX515
Software: Linux kernel 2.6.31
Target requirement: show "boot failed !" in LCD while Linux kernel panic.
Technology methods: use Notifier chains of kernel to do.
Reference to:
[1]. http://bbs.chinaunix.net/thread-2011776-1-1.html
[2]. Linux kernel source code tree: /include/linux/notifier.h, kernel/notifier.c
Modification souce code:
drivers/video/console/fbcon.c
kernel/panic.c

1. modify drivers/video/console/fbcon.c

1.1 modify function fbcon_init()

static void fbcon_init(struct vc_data *vc, int init){/* omit ... *//* show boot information in LCD */#if defined(CONFIG_LOGO_LINUX_CLUT224)show_boot.info = registered_fb[con2fb_map[vc->vc_num]];show_boot.ops = show_boot.info->fbcon_par;show_boot.vc = vc;show_boot.p = &fb_display[vc->vc_num];ret = kernel_thread(show_boot_info_thread, (void *) &show_boot, CLONE_KERNEL);if(ret < 0){pr_err("Failed to start show_boot_info_thread daemon\n");}else{pr_notice("Successful to start show_boot_info_thread daemon\n");}#endif /* CONFIG_LOGO_LINUX_CLUT224 */}

1.2 add below codes in this file

#if defined(CONFIG_LOGO_LINUX_CLUT224)/* Wenxy add begin, 20111014 */struct show_boot_in_lcd{struct fbcon_ops *ops;struct vc_data *vc;struct fb_info *info;struct display *p;};static struct show_boot_in_lcd show_boot; static RAW_NOTIFIER_HEAD(lcd_show_chain); /* show error information in LCD *//* LCD show error information */static int lcd_tip_error(struct notifier_block *this, unsigned long event, void *ptr){struct vc_data *vc;struct fb_info *info;struct fbcon_ops *ops;struct display *p;int yy; int xx;int fg;int bg;unsigned int len;unsigned char tips[]="b o o t   f a i l e d   ! ";if(!show_boot.ops){return -EINVAL;}vc = show_boot.vc;info = show_boot.info;ops = show_boot.ops;p = show_boot.p;xx = 5; /* 62 */yy = 28;fg = 0x04; /* red: 0x04 */bg = 0x7; /* vc->vc_halfcolor; */len = strlen(tips)/2;ops->putcs(vc, info, (unsigned short *)tips, len, real_y(p, yy), real_y(p, xx), fg, bg);return 0; }static struct notifier_block lcd_notifier_error ={        .notifier_call = lcd_tip_error,};int lcd_notifier_call_chain(unsigned long val, void *v){return raw_notifier_call_chain(&lcd_show_chain, 1, NULL);}EXPORT_SYMBOL(lcd_notifier_call_chain);/* Show boot information in LCD */static int show_boot_info_thread(void * dummy){struct vc_data *vc;struct fb_info *info;struct fbcon_ops *ops;struct display *p;const unsigned short *s;int count; int yy; int xx;int fg;int bg;int softback_lines;int mode;unsigned int n, index, len1, len2;#define FM_VERSION "Firmware version: " /* UTS_RELEASE */unsigned char version[256], substr1[128], substr2[128];unsigned char bar[]="                                                                                                                                                                       ";unsigned int time_count, pass_count, bar_count;#define SLEEP_MS100/* millisecond, 100,500 */#define BOOT_KERNEL_TIME10/* second, 10 */#define BAR_LEN90/* boot progress bar length */if(!dummy){return -EINVAL;}vc = ((struct show_boot_in_lcd *)dummy)->vc;info = ((struct show_boot_in_lcd *)dummy)->info;ops = ((struct show_boot_in_lcd *)dummy)->ops;p = ((struct show_boot_in_lcd *)dummy)->p;time_count = (BOOT_KERNEL_TIME*1000)/SLEEP_MS;pass_count = 1;/*time_count = 180;pass_count = 1;bar_count = BAR_LEN/time_count;*//* register notifier block */if(raw_notifier_chain_register(&lcd_show_chain, &lcd_notifier_error)){pr_warning("Warning: into %s, %s, raw_notifier_chain_register call failed\n", __FILE__, __FUNCTION__);}/* show version in LCD */memset(substr1, 0, sizeof(substr1));memset(substr2, 0, sizeof(substr2));memset(version, 0, sizeof(version));memcpy(substr1, FM_VERSION, sizeof(FM_VERSION));memcpy(substr2, UTS_RELEASE, sizeof(UTS_RELEASE));len1 = 2*strlen(FM_VERSION);index = 0;for(n = 0; n < len1; n+=2){version[n] = substr1[index++];version[n+1] = ' ';}len2 = 2*strlen(UTS_RELEASE);index = 0;for(n = 0; n < len2; n+=2){version[len1 + n] = substr2[index++];version[len1 + n+1] = ' ';}/*pr_notice("Debug:%s\n", version);*/xx = 55; /* 62 */yy = 28;fg = 0x00; /* 0x00 */bg = 0x7; /* vc->vc_halfcolor; */ops->putcs(vc, info, (unsigned short *)version, (len1+len2)/2, real_y(p, yy), real_y(p, xx), fg, bg);/* draw progress bar in LCD */xx = 5;yy = 26;fg = 0x7;bg = fg;ops->putcs(vc, info, (unsigned short *)bar, BAR_LEN, real_y(p, yy), real_y(p, xx), fg, bg);while(pass_count <= time_count){xx = 5;yy = 26;fg = 0x2;bg = 0x2;ops->putcs(vc, info, (unsigned short *)bar, pass_count>BAR_LEN?BAR_LEN:pass_count, \real_y(p, yy), real_y(p, xx), fg, bg);/*ops->putcs(vc, info, (unsigned short *)bar, pass_count*bar_count, \real_y(p, yy), real_y(p, xx), fg, bg);*/pass_count++;#if 0ops->cursor_flash = 0; /* stop cursor flash */vc->vc_x = 0; /* Cursor position */vc->vc_y = 0;vc->vc_deccm = 0;/* Cursor cannot Visible */#endifmdelay(SLEEP_MS);}pr_notice("Successful to exit show_boot_info_thread daemon\n");#if 0vc->vc_deccm = 1;ops->cursor_flash = 1;#endif/* unregister notifier block */if(raw_notifier_chain_unregister(&lcd_show_chain, &lcd_notifier_error)){pr_warning("Warning: into %s, %s, raw_notifier_chain_unregister call failed\n", __FILE__, __FUNCTION__);}return 0;}/* Wenxy add end */#endif /* LOGO_LINUX_CLUT224 */

2. modify kernel/panic.c
2.1 add the code in this file

extern int lcd_notifier_call_chain(unsigned long val, void *v);

2.2 modify function panic()

/** *panic - halt the system *@fmt: The text string to print * *Display a message, then perform cleanups. * *This function never returns. */NORET_TYPE void panic(const char * fmt, ...){static char buf[1024];va_list args;long i;#if defined(CONFIG_LOGO_LINUX_CLUT224)/* notification show error information in LCD */if(lcd_notifier_call_chain(1, NULL)){pr_warning("Warning: into %s, %s, lcd_notifier_call_chain call failed\n", __FILE__, __FUNCTION__);}/*mdelay(1 * 1000);*/#endif /* LOGO_LINUX_CLUT224 *//* * It's possible to come here directly from a panic-assertion and * not have preempt disabled. Some functions called from here want * preempt to be disabled. No point enabling it later though... */preempt_disable();bust_spinlocks(1);va_start(args, fmt);vsnprintf(buf, sizeof(buf), fmt, args);va_end(args);printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);#ifdef CONFIG_DEBUG_BUGVERBOSEdump_stack();#endif/* omit ... */}

3. conifg Kernel
#make menuconfig
Select this menu items
Device Drivers ---> Graphics support ---> [*] Bootup logo ---> [*] Standard 224-color Linux logo (NEW)

4. build Kernel
#make -j 4; make uImage



原创粉丝点击