博文

目前显示的是 七月, 2010的博文

通过内核获取config文件

有两种方法,但前提是需要配置了,才能在编译好的内核中再获取config文件。貌似是一个蛋生鸡,鸡生蛋的纠结问题。 但,有时候,我们需要配置内核运行。因此,一般是需要获得一个既有的能跑的config文件。下面介绍的这两种获取config的方法就是用于此目的的。 首先,说一下方法: 法1.在运行的内核中的/proc/config.gz 保存的便是配置文件了 法2.通过/usr/src/linux/scripts/extract-ikconfig 脚本获得一个已经编译好的内核。 这两种方法的前提是,获取内核config的内核在编译的时候,下面的两项被选中了。 CONFIG_IKCONFIG This option enables the complete Linux kernel ".config" file contents to be saved in the kernel. It provides documentation of which kernel options are used in a running kernel or in an on-disk kernel. This information can be extracted from the kernel image file with the script scripts/extract-ikconfig and used as input to rebuild the current kernel or to build another kernel. It can also be extracted from a running kernel by reading /proc/config.gz if enabled (below). 如果这一项配置了,那么通过脚本extract-ikconfig获得config文件 CONFIG_IKCONFIG_PROC This option enables access to the kernel configuration file through /proc/config.gz. 如果这一项配置了,那么

shell脚本后台执行的若干总结

命令后面直接加上&的幼儿园方法不讨论,因为解决不了问题。 shell关闭了,但仍然让脚本执行的方法: 1. nohup 就是忽略掉了父进程hungup信号,继续执行。默认是将脚本所有的输出,输出到了/dev/null或者 nohup.out. 2.用setsid的方法,让脚本的父进程设置为init,这样,关闭shell,脚本照样执行。但对于有输出的脚本程序就不行了,那么用什么方法捏?可以指定其标准输出和错误输出都到/dev/null中。 setsid python /opt/proxy/localproxy/proxy.py > /dev/null 2>&1 另外,搞清楚: command >/devnull 2>&1 与 command > /dev/null 2>/dev/null 其区别不解释. 对于xterm远程登录,可能掉线的情况,推荐方法是用screen.这样可以续上原来的session. screen的具体用法不解释。

Linux设备注册

在加载驱动之前,设备最先被加载。其中最主要的就是资源的注册了。本文简要介绍一些注册的一些过程。 最初,是要准备设备的资源,然后被初始化。 拿imx的MMC为例,其他的与之相同。 arch/arm/mach-imx/gener.c static struct resource imx_mmc_resources[] = { [0] = { .start = 0x00214000, .end = 0x002140FF, .flags = IORESOURCE_MEM, }, [1] = { .start = (SDHC_INT), .end = (SDHC_INT), .flags = IORESOURCE_IRQ, }, }; Coment:设备的资源定义一般都位于arch/arm/mach-机器类型目录下面的文件中。 static struct platform_device imx_mmc_device = { .name = "imx-mmc", .id = 0, .num_resources = ARRAY_SIZE(imx_mmc_resources), .resource = imx_mmc_resources, }; 最初的设备定义仅此而已。 然后,看一下注册是经过怎样的流程: void __init imx_map_io(void) { iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc)); } static struct platform_device *devices[] __initdata = { &imx_mmc_device, &imxfb_device, &imx_uart1_device, &imx_uart2_device, }; static int __init imx_init(void) { return platform_add_devices(d

关于位域

位域,就是在某些结构的成员变量后面加了冒号后跟一个十进制的数子,比如: struct str { int a:1; }类似的定义在kernel中经常碰到。先看一个例子: #include typedef struct test { unsigned int a:1; int b; }Test; Test tt; void main() { tt.a=1,tt.b=100; printf("tt.a:%d,tt.b:%d\n",tt.a,tt.b); tt.a=0,tt.b=100; printf("tt.a:%d,tt.b:%d\n",tt.a,tt.b); tt.a=2,tt.b=100; printf("tt.a:%d,tt.b:%d\n",tt.a,tt.b); tt.a=3,tt.b=100; printf("tt.a:%d,tt.b:%d\n",tt.a,tt.b); } 运行结果: omycle@omycle-desktop:~$ ./a tt.a:1,tt.b:100 tt.a:0,tt.b:100 tt.a:0,tt.b:100 tt.a:1,tt.b:100 可以看到,结构体Test成员变量a被定义为unsigned int 中的最低位--LSB,这就决定了非0即1.我们在实验中也验证了确实是这样子的。 那么位域有什么好处呢? 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。 说明 : 1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如: struct bs { unsigned a:4 unsigned :0 /*空域*/ unsigned b:4 /*从下一单元开始存放*/ unsigned c:4 } 这个位

函数指针与typedef

在阅读内核的时候,会遇到不少函数指针的情况。整理了一下,另外,也有c++函数指针的情况。不过清楚了c的函数指针,读c++的函数指针就不困难了。 另外,也要注意弱类型与强类型。 (一)简单的函数指针的应用。 //形式1:返回类型(*函数名)(参数表) char  (*pFun) (int); //声明 char glFun(int a) { return;}         第一行定义了一个指针变量pFun。首先我们根据前面提到的“形式1”认识到它是一个指向某种函数的指针,这种函数参数是一个int型,返回值是 char类型。只有第一句我们还无法使用这个指针,因为我们还未对它进行赋值。         第二行定义了一个函数glFun()。该函数正好是一个以int为参数返回char的函数。我们要从指针的层次上理解函数——函数的函数名实际上就是一个指针,函数名指向该函数的代码在内存中的首地址。         然后就是可爱的main()函数了,它的第一句您应该看得懂了——它将函数glFun的地址赋值给变量pFun。main()函数的第二句中 “*pFun”显然是取pFun所指向地址的内容,当然也就是取出了函数glFun()的内容,然后给定参数为2。这里,我们可能会稍微疑惑一下,对于变量赋值给指针的话是这样子的 int i; int * ptr; ptr=&i 而这里对函数的赋值,直接是ptr=fun().实际上,函数名就是一个地址。在内核的代码中,我们经常能见到在汇编中调用c函数,是直接call fun,来进行的。因此,疑惑终结。 void main() {     pFun = glFun;//赋值     (*pFun)(2); }   (二)使用typedef更直观更方便。 //形式2:typedef 返回类型(*新类型)(参数表) typedef char (*PTRFUN)(int);         typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型,并定义这种类型为指向某种函数的指针,这种函数以一个int为参数并返回 char类型。后面就可以像使用int,char一样使用PTRFUN了。         第二行的代码便使用这个新类型定义了变量pFun,此时就可以像使用形式1一样使用这个变量了。 PTRFUN pFun; //声明

EmbeddedXENVIRQ发送流程

图片
Hypervisor发送virq的函数有两个: 一个是send_geust_vcpu_virq,另一个是send_guest_global_virq void send_guest_vcpu_virq(struct vcpu *v, int virq) {     int port;     ASSERT(!virq_is_global(virq));     port = v->virq_to_evtchn[virq];     if ( unlikely(port == 0) ) {         return;     }      evtchn_set_pending (v, port); } void send_guest_global_virq(struct domain *d, int virq) {     int port;     struct vcpu *v;     struct evtchn *chn;     ASSERT(virq_is_global(virq));     if ( unlikely(d == NULL) )         return;     v = d->vcpu[0];     if ( unlikely(v == NULL) )         return;     port = v->virq_to_evtchn[virq];     if ( unlikely(port == 0) )         return;     chn = evtchn_from_port(d, port);      evtchn_set_pending (d->vcpu[chn->notify_vcpu_id], port); } send_guest_vcpu_virq的调用关系是这样的: 图中的两个定时器是在分配vcpu的时候安装的。 send_guest_global_virq的调用关系比较复杂,都是发给DOM0的

EmbeddedXEN VIRQ申请

为了说明VIRQ,拿时间中断的注册为例来说明Virq的申请过程,明白了VIRQ申请过程后,我们简单的看一下DOMU console的注册过程。 arch/arm/mach-pxa/time-xen.c MACHINE_START( MAINSTONE , "Intel HCDDBBVA0 Development Platform (aka Mainstone) / EmbeddedXEN (xen-pxa270-qemu)") /* Maintainer: MontaVista Software Inc. */ .phys_io = 0x40000000, .boot_params = 0xa0000100, /* BLOB boot parameter setting */ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .timer = & pxa_timer , .init_machine = mainstone_init MACHINE_END struct sys_timer pxa_timer  = { .init =  pxa_timer_init , /* .suspend = pxa_timer_suspend, .resume = pxa_timer_resume, */ .offset = pxa_gettimeoffset, }; -----------------好了,上面是数据结构,以及定义,现在看一下怎么用这些数据的----- init/main-xen.c asmlinkage void  __init start_kernel_lx0(void) {     ......      time_init();  /* (DRE) xen guest */     ...... } arch/arm/kernel/time.c void __init time_init(void) { if (system_timer->offset == NULL) system_timer->offset = dummy_gettimeoffset; system_timer->init() ; #ifdef CONFIG_NO