全部博文(48)
分类: LINUX
2013-02-21 17:20:03
initrd 本质上就是ramdisk,用来存储数据的。至于是什么数据,就是硬盘上的整个文件系统的阉割版,简而言之就是Busybox,王家卫的《一代宗师》给我的感觉,反胃!赵本山说一个门派,要有人做里子,有人做面子。面子要光彩夺目,容不的不干净的东西。里子就要去面子做下三烂的勾当。内核要自己纯净一些,不要杂七乱八的东西。initrd就是里子,就要替内核着想。系统启动时需要挂载文件系统,可是文件系统是在硬盘上的,需要驱动。所以initrd里面就包含了kernel需要用到的驱动。等kernel用驱动挂载了文件系统,initrd就被卸磨杀驴了。
如何制作initrd, dd 、编译并copy busybox,到dd出来的文件里,这就ok了。
Bootstrap parameters
splash: 貌似是背景吧。
Ramdisk
What is a RAM disk? A RAM disk is a portion of RAM which is being used as if it were a disk drive. RAM disks have fixed sizes, and act like regular disk partitions. Access time is much faster for a RAM disk than for a real, physical disk. However, any data stored on a RAM disk is lost when the system is shut down or powered off. RAM disks can be a great place to store temporary data.
mkfs.ext4 /dev/ram0 & mount /dev/ram0 /mnt
initcall
#define pure_initcall(fn) __define_initcall("0",fn,0)
#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
核心思想就是把所有的init函数编译相同的segment里,内核启动时do_one_initcall调用,从0开始执行。
特别说下pure表示不需要其他的依靠,可以直接执行。可是net_ns_init和net_dev_init反了吧。
Kernel logging
/proc/sys/kernel/printk
dmesg
hlist
hlist_node的成员有一个hlist_node ** pprev,不是普通的一级指针。为什么这样?原因还得从内存紧张说起,hlist_head,只有一个fist指针,为了省内存。既然是循环链表那么第一个hlist_node就得指向即头,可类型是hlist_head,这样hlist_node再用prev指向hlist_head就不和谐了,可是头有一个hlist_node的指针,每个节点也有这个指针所以pprev指向next的地址。
Notifier chains
只是简单的事件相应机制,核心还是callback函数没有什么新意。callback函数会被封装到notifier_block当中。显然我们会把由联系的notifier_block,放到一个链表。为什么放到一块,效率!struct raw_notifier_head 就是这个集合的头!notifier block分为4类,atomic在中断中,blocking进程上下文中,raw你自己看着用,sruc这种还不理解Sleepable Read-Copy Update mechanism 自己google吧。操作notifier_chain_register()用来注册nb,notifier_chain_register一般由驱动调用,唤醒notifier block的callback function。当然内核也会调用。
Variable arguments
我又一次将问题复杂化了。
typedef char *va_list;
//向上 or 向下对齐大小
#define _AUPBND (sizeof (acpi_native_int) - 1)
#define _ADNBND (sizeof (acpi_native_int) - 1)
//对齐后的size
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
//va_arg, 很巧。先加上一个size,ap指向下一个参数,之后减去一个size,再取值,即ap旧的值。
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap) (void) 0
//指向第二个参数,你还记得x86是如何传参的吗?先压右面的参数。为什么不是左面?stack是从高向低生长的!
//也正因为这样的入栈方式,最后入栈的是参数列表上的第一个参数(下例的“1”)在stack的低地址处。通过这个地址找到全部参数,这就是Variable arguments的红肚兜,其实没什么。
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
For example:void arg_test(1, 2, 3, 4)
void arg_test(int i, ...)//从下面的调用可知 i == 1, ... == 2 3 4
{va_list va; //临时指针,起到迭代器的作用。
va_start(va, i); // va == &2,
va_arg(va,int);//返回值 2,va ==&3
va_arg(va,int);//返回值 3, va== &4
va_end(va);
}
最开始,在股票市场,typewriter + wires + ticker tape priter。 很简单的组合,目地就是为了打印出股票价格。
后来,概念被拓展了涉及到网络Teletype + telex(网络) ,此时还是和计算机没关系。
事情变味了,Terminal(VT-100)+ wires + computer(可多任务的大型机)
一发不可收拾,Keboard,VGA monitor + Terminal emulator(in computer)
linux console 和 gnome terminal 都是 terminal emulator,功能上是没有区别的, 实现上console是由 kenrel 提供。 gnome-terminal是构筑在 X上的。
tty
Virtual console:
/dev/tty1 就是virtual console对应Ctrl + alt + F1, X出现后virtual console用的就少了。
/dev/tty0 从用户角度看正在使用(foreground)的virtual console前使用的virtual console,tty0 只能指代virtual console,不能指代X下的pty。
/dev/tty 在进程的task_struct 会保存一个使用的终端,tty就关联到进程里的这个终端。从进程角度出发,和用户正在使用那个foreground 终端无关,可以代表virutal console 和pty 等。
/dev/console 就是内核启动命令的传参那个,一般和tty0一样,可能指定为ttys0.
Carriage return
Typewriter’s carriage /r 13
Line feed /n 10
newline linux /n windows /r/n
指pid 1到桌面启动过程。
sentinel