您的位置:首页 > 运维架构 > Linux

When Linux kernel panic, what can we do ?

2011-10-26 15:37 381 查看
注意: 版权所有, 转载请注明出处.

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_MS			100	/* millisecond, 100,500 */
#define BOOT_KERNEL_TIME	10	/* second, 10 */
#define BAR_LEN				90	/* 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
= 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 0
ops->cursor_flash = 0; /* stop cursor flash */
vc->vc_x = 0; 		/* Cursor position */
vc->vc_y = 0;
vc->vc_deccm = 0;	/* Cursor cannot Visible */
#endif

mdelay(SLEEP_MS);
}

pr_notice("Successful to exit show_boot_info_thread daemon\n");
#if 0
vc->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_BUGVERBOSE
dump_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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息