momo zone

调核人的blog

Monthly Archives: 四月 2012

DB-25并口测试

实验目标
在 PC 机上的并口延长线上接一 LED ,通过使用 /dev/port 设备文件控制 LED 闪动。

实验步骤

1、在 BIOS 里把并口模式改为 SPP

SPP ( Sequenced Packed Protocol ,序列分组协议 ) 是标准模式,它与 EPP 和 ECP 不同,是早期定义的规范 ( Centronic ) ,其结构简单且各 PC 类型都可支持。这里,打印机接口地址为 0x378 ,中断号为 7。
( EPP/ECP < Enhanced Parallel Port/Enhanced Capability Port > 是计算机与设备之间的双向并行通信规范,提供比 SPP 并行信号传送更快的数据通信速度。EPP 用于除了打印机以外的设备,而 ECP 是用于打印机和扫描仪。 )

打印机并口有 25 个引脚,其中有 17 条信号线和 8 条地线。8 条地线为 18~25 。信号线中有 4 条控制线条 ( Control Line)、5 条状态线 ( Status Line )、8条数据线 ( Data Line )。控制线用于 PC 机向打印机的连接和握手信号,状态线是用于反映打印机的状态,数据线是用于 PC 机向打印机发送数据。有 3 个与控制打印机相关的寄存器,其地址位于 PC 的 I/O 地址列表内。一般打印机的端口地址为 0x378, 0x379, 0x37A 。只要向对应的寄存器写入数据,其硬件将输出相反的内容。相反,施加到硬件的信号也可以通过寄存器获取。

0x378 控制的引脚为 2~9 (data0~data7),方向为输出。

0x379 控制第 11 脚(busy),方向为输出 ,bit-7;引脚 10,方向为输入 (acknowledge), bit6 ;引脚 12 方向为输入(out of paper),bit-5;引脚13,方向为输入(select), bit-4;引脚15,方向为输入, 比(error),bit-3;bit0~bit2 不用。

0x37A 的 bit5~bit7 未用;bit-4 为 IRQ 控制使能;bit-3 控制引脚 17 (select input 的反向输出),方向为输出;bit-2 控制引脚 16 (init),方向为输出;bit-1控制引脚 14 (auto feed 的反向输出),方向为输出;bit-0 控制引脚 1 (strobe 选通),方向为输出。

2、测试程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int fd;
int lp;unsigned char buff [128];fd = open(“/dev/port”, O_RDWR);
if (fd < 0) {
perror(“/dev/port open error”);
exit(1);
}
for (lp = 0; lp < 10; lp++) {
lseek(fd, 0x378, SEEK_SET);
buff [0] = 0xFF;
write(fd, buff, 1);
sleep(1);
lseek(fd, 0x378, SEEK_SET);
buff [0] = 0x00;
write(fd, buff, 1);
sleep(1);
}
close (1);

return 0;
}

3、运行效果

LED 灯会以 2 秒的时间间隔闪烁。

4、说明
大开 /dev/port 设备文件仍用底层 open() 函数大开。如果正常打开设备后文件,则通过 lseek() 函数把地址指定为文件端口值。这也是 /dev/port 设备文件的设备驱动程序的特征。然而,并不是说所有的设备文件的驱动程序都具有这样的特征。在 lseek() 函数执行后,文件端口的位置就被指定为 0x378。lseek() 的第三个参数 SEEK_SET 表明直接转向文件端口值 0x378。

/dev/port 设备文件可以使应用程序直接接触系统的 I/O 端口。

apt 和 dpkg用法

工作原因要开始用debian ,备忘一下其下包管理工具

=======
apt-get
=======
1.apt-get update

-d 仅下载
-f 强制安装
更新套件資訊,要升級之前,最好都先執行一次本指令和 Server 端的資訊同步一下

2.apt-get check
檢查你系統上套件的相依性狀況

3.apt-get dist-upgrade 和 apt-get upgrade
執行整個升級動作,建議用 apt-get dist-upgrade 比較好

4.apt-get install 套件名稱
安裝某一個套件及其相關的套件
如 apt-get install xcin
這樣就會幫您安裝好 xcin 了,連 libtabe 也會一併幫您安裝好

5.apt-get remove 套件名稱 (若想含設定檔等完整移除: apt-get –purge remove 套件名稱)
移除某套件,和 rpm -e 功能一樣,同時還會幫您把相關的套件一併移除

6.apt-get source 套件名稱
抓回 source rpm
例: apt-get source –compile zhcon
抓回 source rpm 並編譯成 binary rpm
–compile 參數就如同 rpm -ba 一般

7.apt-get clean
刪除下載回來的檔案

=========
apt-cache
=========
1.apt-cache showpkg
顯示套件資訊
例: apt-cache showpkg zhcon

2.apt-cache stats
顯示相關的統計資訊

3.apt-cache dump
顥示 cache 中每個套件的簡短資訊

4.apt-cache unmet
檢查所有未符合相依性的相關資訊

5.apt-cache show
顯示套件資訊,同 rpm -qi 一般

6.apt-cache search
尋找檔案
例: apt-cache search zhcon

7.apt-cache depends
顯示套件的相依性
例: apt-cache depends zhcon

8.apt-cache pkgnames
尋找符合的套件名稱
例: $ apt-cache pkgnames openss
openssh-askpass
openssl096
openssl-perl
openssl095a
openssl-python
openssh-clients
openssl-devel
openssh-askpass-gnome
openssh
openssl
openssh-server

==========
apt-config
==========
1.apt-config dump
顯示目前的設定狀態

==========

dpkg

==========

dpkg -i | –install xxx.deb 安装deb软件包
dpkg -r | –remove xxx.deb 删除软件包
dpkg -r -P | –purge xxx.deb 连同配置文件一起删除
dpkg -I | -info xxx.deb 查看软件包信息
dpkg -L xxx.deb 查看包内文件
dpkg -l 查看系统中已安装软件包信息
dpkg-reconfigure xxx 重新配置软件包

在内核构造skb 简单示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <net/route.h>
#include <net/icmp.h>
#include <linux/netfilter_ipv4.h>
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“kenthy@163.com”);
#define    ETH     “eth0”
#define    SIP     “192.168.238.180”
#define    DIP     “192.168.1.101”
#define    SPORT   39804
#define    DPORT   80
unsigned char   SMAC[ETH_ALEN] = {0x00,0x0C,0x29,0x4F,0xDE,0xAC};
unsigned char   DMAC[ETH_ALEN] = {0x00,0x50,0x56,0xFA,0x70,0x2A};
int cp_dev_xmit_tcp (char * eth, u_char * smac, u_char * dmac,
u_char * pkt, int pkt_len,
u_long sip, u_long dip,
u_short sport, u_short dport, u_long seq, u_long ack_seq, u_char psh, u_char fin)
{
struct sk_buff * skb = NULL;
struct net_device * dev = NULL;
struct ethhdr * ethdr = NULL;
struct iphdr * iph = NULL;
struct tcphdr * tcph = NULL;
u_char * pdata = NULL;
int nret = 1;
if (NULL == smac || NULL == dmac) goto out;
dev = dev_get_by_name(eth);
if (NULL == dev)
goto out;
skb = alloc_skb (pkt_len + sizeof (struct iphdr) + sizeof (struct tcphdr) + LL_RESERVED_SPACE (dev), GFP_ATOMIC);
if (NULL == skb)
goto out;
skb_reserve (skb, LL_RESERVED_SPACE (dev));
skb->dev = dev;
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = __constant_htons(ETH_P_IP);
skb->ip_summed = CHECKSUM_NONE;
skb->priority = 0;
skb->nh.iph = (struct iphdr*)skb_put(skb, sizeof (struct iphdr));
skb->h.th = (struct tcphdr*)skb_put(skb, sizeof (struct tcphdr));
pdata = skb_put (skb, pkt_len);
{
if (NULL != pkt)
memcpy (pdata, pkt, pkt_len);
}
{
tcph = (struct tcphdr *) skb->h.th;
memset (tcph, 0, sizeof (struct tcphdr));
tcph->source = sport;
tcph->dest = dport;
tcph->seq = seq;
tcph->ack_seq = ack_seq;
tcph->doff = 5;
tcph->psh = psh;
tcph->fin = fin;
tcph->syn = 1;
tcph->ack = 0;
tcph->window = __constant_htons (5840);
skb->csum = 0;
tcph->check = 0;
}
{
iph = (struct iphdr*) skb->nh.iph;
iph->version = 4;
iph->ihl = sizeof(struct iphdr)>>2;
iph->frag_off = 0;
iph->protocol = IPPROTO_TCP;
iph->tos = 0;
iph->daddr = dip;
iph->saddr = sip;
iph->ttl = 0x40;
iph->tot_len = __constant_htons(skb->len);
iph->check = 0;
}
skb->csum = skb_checksum (skb, iph->ihl*4, skb->len – iph->ihl * 4, 0);
tcph->check = csum_tcpudp_magic (sip, dip, skb->len – iph->ihl * 4, IPPROTO_TCP, skb->csum);
skb->mac.raw = skb_push (skb, 14);
{
ethdr = (struct ethhdr *)skb->mac.raw;
memcpy (ethdr->h_dest, dmac, ETH_ALEN);
memcpy (ethdr->h_source, smac, ETH_ALEN);
ethdr->h_proto = __constant_htons (ETH_P_IP);
}
if (0 > dev_queue_xmit(skb)) goto out;
nret = 0;
out:
if (0 != nret && NULL != skb) {dev_put (dev); kfree_skb (skb);}
return (nret);
}
static int __init init(void)
{
printk(“%s/n”,”insmod skb_diy module/n”);
cp_dev_xmit_tcp (ETH, SMAC, DMAC,NULL, 0,
in_aton(SIP),in_aton(DIP),
htons(SPORT),htons(DPORT),
0, 0, 0, 0);
return 0;
}
static void __exit fini(void)
{
printk(“%s/n”,”remove skb_diy module./n”);
}
module_init(init);
module_exit(fini);

我这里并没有填充上层的东西 但是已经提供接口
pdata = skb_put (skb, pkt_len);
{
if (NULL != pkt)
memcpy (pdata, pkt, pkt_len);
}

panic 流程

内核在发生严重错误的时候要“X屏”一下,以windows为例就是蓝屏,而linux却是黑屏,windows仅仅提供一个出错码和对应地址,十分难以 理解,而linux却可能提供整个寄存器和堆栈,它不隐瞒一切,代码公开,当然出错时的环境就没有必要隐瞒了,首先看一下panic:

NORET_TYPE void panic(const char * fmt, …)

{

long i;

static char buf[1024];

va_list args;

preempt_disable(); //关闭抢占,否则此cpu执行到后面的死循环时还是有可能被抢占的,被抢占意味着可以切换到别的进程,但是在panic里,这是不希望的,企图出去 panic函数的任何行为都是不希望的。注意,这里关闭了抢占就再也不打开了。

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); //非常熟悉的一句话,后面接panic原因的文字描述

bust_spinlocks(0);

crash_kexec(NULL); //如果事先设定了kexec的内核就开始启动另一个内核,panic流程到此结束

#ifdef CONFIG_SMP

smp_send_stop();//要求别的cpu执行halt,实际上就是停止了别的cpu,而本cpu即导致panic的cpu最终将死循环。

#endif

atomic_notifier_call_chain(&panic_notifier_list, 0, buf);//处理panic通知链,有些程序会在此时被触发比如kgdb

if (!panic_blink)

panic_blink = no_blink;

if (panic_timeout > 0) {  //重启延时如果不为0则倒计时重启。

printk(KERN_EMERG “Rebooting in %d seconds..”,panic_timeout);

for (i = 0; i < panic_timeout*1000; ) {  //只能用这种方式来倒计时了,进入panic意味着出现严重错误,因此最好呆在panic里面,不要触及外面的任何东西,timer这时可能已经不好用了,因此就用这种方式吧,否则将导致更严重的错误。

touch_nmi_watchdog();

i += panic_blink(i);

mdelay(1);

i++;

}

emergency_restart(); //重新启动

}

local_irq_enable();  // 打开了中断,因此在下面的死循环里还是可以响应中断的,但是如果是在中断上下文中引起panic,即in_interrupt()为真的情况引 起 panic的话,虽然硬件中断可以响应但是软中断就不可响应了,因为软中断执行时in_interrupt()必须为假才行。

for (i = 0;;) {

touch_softlockup_watchdog(); //复位一次watchdog,到了这个地步不要让狗再触发一次soft lockup的panic 了

i += panic_blink(i);

mdelay(1);

i++;

}

}

由 上述panic可以看出,panic并没有什么大不了的,就是禁抢占,善后,禁止了抢占实际上就禁止了调度,因为禁止抢占的情况下除非自己放弃cpu才能 调度,但是我们看看那个死循环根本没有放弃cpu的意思。发生panic无非就两种情形,一个是在中断上下文,另一个是在非中断上下文。在中断上下文中 panic的话,此时的in_interrupt()一定返回真,如果此硬件中断触发了一个软中断,那么这个软中断是永远不会被执行的,因为导致 panic的中断永远不会调用irq_exit来使得in_interrupt()返回假。这就解释了为何在中断中panic的系统ping不通,而在非 中断上下文中panic虽然内核死掉了但是还是可以从外部ping通的。想想ping的执行,ping依靠的是icmp协议,没有进程上下文,它是ip层 的内容,而ip层是不区分进程的,于是icmp的处理只在软中断上下文进行,既然硬件中断中panic了,根据上面的论述,软中断就没有机会执行了,于是 就ping不通了;而非中断的panic由于软中断可以执行,所以可以ping通,但是内核还是不能恢复了,因为已经关闭可抢占,无法调度了,于是执行流出去中断后便会一直执行那个死循环,没有机会执行别的。
这就是panic,从字面意义上就是“惊慌”的意思,如果一个人惊慌了,那么他的行为无非两种,一是失控地四处乱跑,而是在原地惊呆,内核是绝对不会选择 前者的,如果一个人四处乱窜的话,一定会有人帮他镇静,比如警察或者他的家人,要么就是医生,最终还是他要呆在一个地方静止,内核当然是一步到位了,直接不允许乱窜,人在乱窜的时候十有八九会导致事故,比如推翻了桌子,而桌子上有一只很贵的花瓶,内核也考虑到了,为了免得次生破坏,那么直接呆在原地不要动 了。因此你看不见任何出去panic的路子。当然会有一些提示,用来提示发生了严重错误,内核panic,类似于拨打了120电话,在一些平台上就是键盘 灯不停地闪烁。那么在代码中怎么体现呢?可以肯定的是,键盘闪烁一定是死循环中调用的函数的行为,而这个死循环如此之短使得把它揪出来很容易,看看 panic_blink函数,它是一个函数指针,不同的平台指向的函数不同,在大多数x86的pc上就是i8042_panic_blink:

static long i8042_panic_blink(long count)

{

long delay = 0;

static long last_blink;

static char led;

if (!i8042_blink_frequency)

return 0;

if (count – last_blink < i8042_blink_frequency)

return 0;

led ^= 0x01 | 0x04;

while (i8042_read_status() & I8042_STR_IBF)

DELAY;

i8042_write_data(0xed); /* set leds */

DELAY;

while (i8042_read_status() & I8042_STR_IBF)

DELAY;

DELAY;

i8042_write_data(led);

DELAY;

last_blink = count;

return delay;

}

这 个函数还用说吗?只要知道它的作用就完美了,硬件相关的东西如果你没有那个硬件的手册或者是你根本就不需要做那个硬件的相关的东西就没有必要浪费时间去研究,只要知道接口的意义就可以了。在那个死循环里还有一个重要的调用涉及到一个nmi的看门狗,nmi在内核挂起从而需要调试的时候很有用,nmi是 non maskable interrupt的意思,就是不可屏蔽中断,试想当内核挂起,键盘不再响应,甚至中断都不再执行或者无法输出堆栈信息的时候,nmi实际上就有用 了,nmi中断无论如何都要发生,从而nmi的中断处理函数无论如何都要执行,那么就可以在这个中断处理中输出调试信息或进行转储,它可能会调用die函 数,然后引发一个panic,最终输出信息或转储,至于具体代码就不说了。记住,如果发生oops,那么还有一招可以用,就是Alt+Sysrq+X组合 键,X为具体命令,请查手册,比如X为m就是导出内存信息,但是如果组合键都不响应了,那么请看看你的内核是否彻底关中断锁住了,还有就是看看组合键是否在软中断上下文被处理而导致panic的是在硬件中断上下文,起码在2.6内核引入input_dev后,这种情况成为了可能,人们为了追求和谐与统一可 以把一切键盘码的处理都放到软中断,但是却导致了组合键在oops中无法响应的问题
以上谈了panic,下面就看看BUG_ON,这也是一个panic点,但是却不是一定要panic,只有在平台不提供bug验证代码的时候才会调用 panic,因为无法处理这个哪怕小小的bug,那么就可能引发大大的崩溃,而何时引发以及危害如何是不确定的,因此还不如直接panic,停止内核,将以下的事情交给调试人员。看看代码:

#ifndef HAVE_ARCH_BUG_ON

#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)

#endif

以上视为平台没有提供BUG_ON,以下为平台提供了BUG_ON

#ifndef HAVE_ARCH_BUG

#define BUG()

#endif

对于没有提供BUG_ON的平台,内核的定义为在满足条件的时候调用BUG,而BUG定义如下:

#ifndef HAVE_ARCH_BUG

#define BUG() do { /

printk(“BUG: failure at %s:%d/%s()!/n”, __FILE__, __LINE__, __FUNCTION__); /

panic(“BUG!”); /

} while (0)

#endif

可以看出最终调用了panic,内核就此game over,而对于平台的BUG_ON,这里以i386为例:(2.6.17内核)

#define BUG() __asm__ __volatile__(“ud2/n”)

ud2 在x86上是无效指令,执行之会引发错误从而输出堆栈或转储,但是看出问题了吗?仅仅一条无效指令导致堆栈回溯,然后呢?然后当然就恢复正常了,这难道是希望的行为吗?出错信息显然导到终端,但是是否所有人都会在意终端的输出呢?更好的做法应该是一旦BUG()被调用,立马挂起内核,像panic那样,但 是不善后。实际上内核中的任何哪怕非常小的bug都可能导致严重的后果,因此不要忽略任何bug,并且不要放过它。于是在2.6.20以及以后的内核的 BUG宏的定义就改变了:

#define BUG()                                                           /

do {                                                            /

asm volatile(“ud2”);                                    /

for(;;) ;                                               /

} while(0)

但是还是有问题,就是for循环在抢占打开的情况下可以被抢占,不过这个问题看似没有那么严重,毕竟严重错误的时候内核就直接panic了,而BUG只是一些不希望的事情确实发生了时候才调用的,最起码它停掉了一条执行流,该条执行流将永远堵在for循环里,万劫不复!

hard panic

一般出现下面的情况,就认为是发生了kernel panic:

  1. 机器彻底被锁定,不能使用
  2. 数字键(Num Lock),大写锁定键(Caps Lock),滚动锁定键(Scroll Lock)不停闪烁。
  3. 如果在终端下,应该可以看到内核dump出来的信息(包括一段”Aieee”信息或者”Oops”信息)
  4. 和Windows蓝屏相似

原因:

对于hard panic而言,最大的可能性是驱动模块的中断处理(interrupt handler)导致的,一般是因为驱动模块在中断处理程序中访问一个空指针(null pointre)。一旦发生这种情况,驱动模块就无法处理新的中断请求,最终导致系统崩溃。

soft panic

症状:

  1. 没有hard panic严重
  2. 通常导致段错误(segmentation fault)
  3. 可以看到一个oops信息,/var/log/messages里可以搜索到’Oops’
  4. 机器稍微还能用(但是收集信息后,应该重启系统)

原因:

凡是非中断处理引发的模块崩溃都将导致soft panic。在这种情况下,驱动本身会崩溃,但是还不至于让系统出现致命性失败,因为它没有锁定中断处理例程。导致hard panic的原因同样对soft panic也有用(比如在运行时访问一个空指针)

信息收集:
当soft panic发生时,内核将产生一个包含内核符号(kernel symbols)信息的dump数据,这个将记录在/var/log/messages里。为了开始排查故障,可以使用ksymoops工具来把内核符号信息转成有意义的数据。

为了生成ksymoops文件,需要:

  • 从/var/log/messages里找到的堆栈跟踪文本信息保存为一个新文件。确保删除了时间戳(timestamp),否则ksymoops会失败。
  • 运行ksymoops程序(如果没有,请安装)
  • 详细的ksymoops执行用法,可以参考ksymoops(8)手册。

hard lockup

意思是在关中断情况下发生死锁(大多数情况都是在硬中断中),不一定是真的死锁,实际是如果关中断时间太长 ,就会触发hard panic。比如下面的一段代码,在线程环境下:

local_irq_disable();

mdelay(40000);

local_irq_enable();

本地中断被关闭,导致超过30秒时钟中断没有发生,虽然不是在中断环境下,但长时间关闭中断相当于模拟了中断环境下的死循环。于是NMI中断程序(NMI是关不掉的)触发panic ,这个panic就是hard panic。

[ 1123.480906] Kernel panic – not syncing: Watchdog detected hard LOCKUP on cpu 1
[ 1134.945031] ttyS0: 1 input overrun(s)
[ 1123.480906] Pid: 2306, comm: insmod Not tainted 3.1.0-1.3-desktop-mod #1
[ 1123.480906] Call Trace:
[ 1123.480906] [<ffffffff8100441a>] dump_trace+0xaa/0x2b0
[ 1123.480906] [<ffffffff81587c90>] dump_stack+0x69/0x6f
[ 1123.480906] [<ffffffff8158a200>] panic+0xa4/0x1b8
[ 1123.480906] [<ffffffff810c3366>] watchdog_overflow_callback+0xb6/0xc0
[ 1123.480906] [<ffffffff810f05d6>] __perf_event_overflow+0x96/0x200
[ 1123.480906] [<ffffffff81015b34>] intel_pmu_handle_irq+0x194/0x250
[ 1123.480906] [<ffffffff815a3409>] perf_event_nmi_handler+0x29/0xb0
[ 1123.480906] [<ffffffff815a4f55>] notifier_call_chain+0x45/0x60
[ 1123.480906] [<ffffffff815a4fb5>] __atomic_notifier_call_chain+0x45/0x70
[ 1123.480906] [<ffffffff815a501d>] notify_die+0x2d/0x40
[ 1123.480906] [<ffffffff815a2577>] default_do_nmi+0x37/0x220
[ 1123.480906] [<ffffffff815a2948>] do_nmi+0x68/0x70
[ 1123.480906] [<ffffffff815a2330>] nmi+0x20/0x30
[ 1123.480906] [<ffffffff8100a020>] rtc_cmos_write+0x10/0x10
[ 1123.480906] [<ffffffff812c1016>] delay_tsc+0x76/0xf0
[ 1123.480906] [<ffffffffa0005019>] test_init+0x19/0x1000 [test]
[ 1123.480906] [<ffffffff810001ca>] do_one_initcall+0x3a/0x180
[ 1123.480906] [<ffffffff81093418>] sys_init_module+0xb8/0x230
[ 1123.480906] [<ffffffff815a8a52>] system_call_fastpath+0x16/0x1b
[ 1123.480906] [<00007f166d3aec8a>] 0x7f166d3aec89

[ 1123.480906] panic occurred, switching back to text console
[ 1135.142308] ————[ cut here ]————
[ 1135.142308] WARNING: at arch/x86/kernel/smp.c:118 try_to_wake_up+0x161/0x1f0()
[ 1135.142308] Hardware name: 7762WDX
[ 1135.142308] Modules linked in: test(+) af_packet rfcomm bnep cpufreq_conservative microcode cpufreq_userspace cpufreq_powersave acpi_cpufreq mperf dm_mod arc4 ath5k ath mac80211 snd_hda_codec_analog ecb pcmcia btusb joydev snd_hda_intel snd_hda_codec snd_hwdep ppdev thinkpad_acpi snd_pcm sdhci_pci snd_timer sr_mod bluetooth sdhci cdrom pcspkr i2c_i801 sg firewire_ohci ac battery parport_pc parport mmc_core yenta_socket firewire_core cfg80211 tpm_tis pcmcia_rsrc tpm pcmcia_core snd tpm_bios crc_itu_t e1000e iTCO_wdt soundcore snd_page_alloc iTCO_vendor_support rfkill hdaps tp_smapi thinkpad_ec autofs4 i915 drm_kms_helper drm i2c_algo_bit thermal processor video button thermal_sys ata_generic [last unloaded: test]
[ 1135.142308] Pid: 2306, comm: insmod Not tainted 3.1.0-1.3-desktop-mod #1
[ 1135.142308] Call Trace:
[ 1135.142308] [<ffffffff8100441a>] dump_trace+0xaa/0x2b0
[ 1135.142308] [<ffffffff81587c90>] dump_stack+0x69/0x6f
[ 1135.142308] [<ffffffff810533cb>] warn_slowpath_common+0x7b/0xc0       //试图唤醒之前被NMI中断的线程,发现该
[ 1135.142308] [<ffffffff8104b9f1>] try_to_wake_up+0x161/0x1f0                       //线程睡了很久,就再报一次kernel taint,之后
[ 1135.142308] [<ffffffff810761c9>] autoremove_wake_function+0x9/0x30     //继续执行panic流程中的LED闪灯代码,我明白,我要去按reset了~
[ 1135.142308] [<ffffffff81039128>] __wake_up_common+0x58/0x90
[ 1135.142308] [<ffffffff8103a963>] __wake_up+0x43/0x70
[ 1135.142308] [<ffffffff810649e4>] update_process_times+0x44/0x80
[ 1135.142308] [<ffffffff810870eb>] tick_sched_timer+0x5b/0xc0
[ 1135.142308] [<ffffffff81079c4e>] __run_hrtimer+0x6e/0x240
[ 1135.142308] [<ffffffff8107a675>] hrtimer_interrupt+0xe5/0x200
[ 1135.142308] [<ffffffff8101e8a3>] smp_apic_timer_interrupt+0x63/0xa0
[ 1135.142308] [<ffffffff815a959e>] apic_timer_interrupt+0x6e/0x80                  //panic里打开了中断,这里进入了中断程序
[ 1135.142308] [<ffffffff8158a2d1>] panic+0x175/0x1b8
[ 1135.142308] [<ffffffff810c3366>] watchdog_overflow_callback+0xb6/0xc0
[ 1135.142308] [<ffffffff810f05d6>] __perf_event_overflow+0x96/0x200
[ 1135.142308] [<ffffffff81015b34>] intel_pmu_handle_irq+0x194/0x250
[ 1135.142308] [<ffffffff815a3409>] perf_event_nmi_handler+0x29/0xb0
[ 1135.142308] [<ffffffff815a4f55>] notifier_call_chain+0x45/0x60
[ 1135.142308] [<ffffffff815a4fb5>] __atomic_notifier_call_chain+0x45/0x70
[ 1135.142308] [<ffffffff815a501d>] notify_die+0x2d/0x40
[ 1135.142308] [<ffffffff815a2577>] default_do_nmi+0x37/0x220
[ 1135.142308] [<ffffffff815a2948>] do_nmi+0x68/0x70
[ 1135.142308] [<ffffffff815a2330>] nmi+0x20/0x30
[ 1135.142308] [<ffffffff8100a020>] rtc_cmos_write+0x10/0x10
[ 1135.142308] [<ffffffff812c1016>] delay_tsc+0x76/0xf0
[ 1135.142308] [<ffffffffa0005019>] test_init+0x19/0x1000 [test]
[ 1135.142308] [<ffffffff810001ca>] do_one_initcall+0x3a/0x180
[ 1135.142308] [<ffffffff81093418>] sys_init_module+0xb8/0x230
[ 1135.142308] [<ffffffff815a8a52>] system_call_fastpath+0x16/0x1b
[ 1135.142308] [<00007f166d3aec8a>] 0x7f166d3aec89
[ 1135.142308] —[ end trace f606e083ac04fd4b ]—

hard lockup detect 机制依赖nmi中断,也就nmi中断响应函数中对kernel/watchdog.c 中watchdog_overflow_callback的调用。注意,这里也可以看出这段代码虽然是在watchdog.c 中,但实际喂狗的不是时钟中断,而是nmi中断。和下面说的soft lockup完全不同

soft lockup

其实就是在没有关中断的情况下发生了lockup,由于在没有关闭硬中断的情况下,正常的话时钟中断应该会被及时响应,时钟中断的处理函数会触发kernel watchdog更新时间戳。如果这种情况下系统非常繁忙以至时钟中断都响应不及时,那么将造成kernel watchdog时间戳间隔过大,那么他将发出侦测到soft lockup的情况。

http://www.diybl.com/course/6_system/linux/Linuxjs/20110503/554874.html

辨识并小心 内核原子环境

今天把一段控制代码移到netlink 回调函数中, 结果一到netlink 流程的某一段kernel就彻底挂了。思来想去,一阵抓耳挠腮后 感觉会不会因为netlink 是中断上下文,而我的控制代码中有睡眠动作的原因 ?   先看了下那段控制代码,大概在第6层调用的时候碰到了vmalloc  ,条件一满足了。 至于netlink是不是中断上下文我就不知道了,幸运的是kernel里面有这样几个宏:

#define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0)

#define in_irq() (hardirq_count())
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())
#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET)

#define hardirq_count() (preempt_count() & HARDIRQ_MASK)
#define softirq_count() (preempt_count() & SOFTIRQ_MASK)
#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
| NMI_MASK))

其中in_interrupt 就是对应hardirq 和softirq 两方。 我插入这个宏测试了一下,发现确实不再中断上下文。 然后郁闷了一下,再试试是否在原子上下文吧。 结果这下命中了,好吧,我刚刚知道netlink 流程是在原子上下文。 接下来怎么改代码呢,把控制逻辑放到工作队列?  这样岂不是变成异步模式了, 不行 ,在想想吧 ……………………………..

icmp tunnel 相关

PS2 BB navigator

事隔十几年,搞了一套PS2 BB unit 弥补了当年的缺憾。 玩玩了HDLOAD ,OPL 感慨无限,完全忘记了放在旁边的PS3 。这两天搞了下BB navigator :

http://www.assemblergames.com/forums/entry.php?23-Install-PSBBN-HDD-OSD-on-other-Region-PS2-Consoles

http://www.assemblergames.com/forums/entry.php?24-Install-APPS-Elfs-to-the-PS2-Browser-Game-Channel%28updated%29

不过现在都2012年了,DNSA 好像已经无法通过认证了。wireshark信息如下:

ainol novo 7 mips android system.img 制作

  1. mkfs.ext2
  2. tune2fs -L system
  3. tune2fs -j
  4. mount and copy file
  5. tune2fs -C 1
  6. e2fsck

done

注意不要超过256MB

我的coding风格

indent -npro -npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 -i10

来自内核的 scripts/Lindent

#!/bin/sh
PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1"
RES=`indent --version`
V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1`
V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2`
V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3`
if [ $V1 -gt 2 ]; then
  PARAM="$PARAM -il0"
elif [ $V1 -eq 2 ]; then
  if [ $V2 -gt 2 ]; then
    PARAM="$PARAM -il0";
  elif [ $V2 -eq 2 ]; then
    if [ $V3 -ge 10 ]; then
      PARAM="$PARAM -il0"
    fi
  fi
fi
indent $PARAM "$@"