标题:[xen3.3.0] __start_xen 函数中启动dom0的简单分析 出处:Felix021 时间:Wed, 01 Jul 2009 17:17:52 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?1679 内容: 本文档分析了xen启动时创建dom0的基本过程,并进行了一些简单的测试,记录了测试结果。 @ xen3.3.0/xen/arch/x86/setup.c ---- line 408 __start_xen(unsigned long mbi_p) @ line 414, multiboot_info_t *mbi = __va(mbi_p); mbi = multiboot_info, 类型multiboot_info_t, 位于include/xen/multiboot.h @ line 415, modile_t *mod = (module_t *)__va(mbi->mods_addr); module_t是一个位于multiboot.h中的struct,包含mod_start, mod_end, string, reserved等4个成员,其中mod_start, mod_end是地址, string是module [file] [para]这里的para字段(参数, 如果没有的话,就是NULL),比如kernel的参数就是这么搞出来的cmdline(大概在997行的位置)。 这个mod是一个指针,取值于mbi_p的成员mods_addr,其实就对应了一个数组,这数组的每一项应该就是顺序地对应着grub启动xen的时候,每一个module行对应的文件载入内存后的信息,包括起始和结束地址,还有附加的参数。 @ line 989, dom0 = domain_create(0, 0, DOM0_SSIDREF); 这里调用create_domain函数,分配一个struct domain的空间,对其进行初始化,然后返回这个地址存入dom0。我们可以仿照这个方式创建另一个struct domain, 比如domB。domain_create函数位于commom/domain.c,声明于include/xen/sched.h,其原型为 struct domain *domain_create( domid_t domid, unsigned int domcr_flags, ssidref_t ssidref) 第一个参数是domid,第二个参数是dom的类型,具体参见sched.h +336(好像有点出入?),第三个参数是用于xen的ssid reference,具体用途和生成方式不明。DOM0_SSIDREF被定义为0x0。 @ line 990, if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) ) 这里检查989行的domain_create是否成功,如果成功,则试图给该domain分配一个vcpu。 @ line 997, cmdline = ... mod[0].string ... 从mod指向的module_t数组的第一个元素中取出kernel的启动参数。默认第一个是内核,第二个是initrd。接下来,如果参数不为空,就将参数进行一定处理,附加一些额外的参数,诸如acpi等,这一段可以忽略, 直到1027。 @ line 1028 if ( (initrdidx > 0) && (initrdidx < mbi->mods_count) ).... initrdidx的初始值为1, 如果这个值小于grub的menu.lst里面对应的module的行数(kernel + initrd,默认应该需要2行module),那么说明是有initrd的,那么就从mod[initrdidx],也就是mod[1],也就是第二个module语句对应的module_t中取出initrd被载入内存后的起始地址和总长度。 @ 1043, if (construct_dom0(dom0, ... 这里是实际建立一个domain的函数了,传入的参数包括一个有效struct domain结构的指针,kernel起始地址和长度,initrd的起始地址和长度,还有kernel的启动参数。返回值为0表示启动成功,否则是失败。 @1061, domain_unpause_by_systemcontroller(dom0); 这个函数激活dom0对应的domain的每一个vcpu,使得domain可以实际运行起来。 ----以上为启动dom0涉及到的过程。 ----下面是进行的一些测试。 测试结果见图simple_test1.png 点击在新窗口中浏览此图片 https://www.felix021.com/blog/attachment.php?fid=348 首先是对grub的一些处理: $ cd /boot $ echo 123 > mini-os.gz $ vi grub/menu.lst 启动xen的几行大致是 title Ubuntu 9.04, kernel 2.6.26.1-xen-686 root (hd0,0) #因为测试机上/boot是单独的一个分区,位于(hd0,0) kernel /xen.gz module /vmlinuz-2.6.26-1-xen-686 root=/dev/sda5 ro splash quiet module /initrd.img-2.6.26-1-xen-686 在其后又加入了一行 module /mini-os.gz 然后对setup.c进行了一些修改,包括: 1. 在995行处加入一段初始化domB的代码 domB = domain_create(0x7777, 0, 0x7777); if ( (domB == NULL) || (alloc_vcpu(domB, 0, 0) == NULL) ) panic("Error creating domain B\n"); domB->is_privileged = 1; domB->target = NULL; printk("OK Creating Domain B\n"); 其中domB定义和声明的位置在dom0定义和声明的位置下方,分别是common/domain.c和include/xen/sched.h。 从途中可以看到,创建domB和为domB分配VCPU的过程都是正确的。 其中的0x7777是随便填的一个数字,没有特殊含义,也不保证此后可以正确运行。 2. 在997行之后加入了一行 printk("-----JUST A TEST\ncmdline = %s\n", cmdline); 由图可以看出,cmdline的确指向了kernel的启动参数。 3. 在1035行的位置加入如下几行,用于打印module的行数、第三个module行对应文件被载入后的地址、以及其前三个字符(及其ASCII码值) printk("mods_count = %d\n", mbi->mods_count); printk("--start char @ [%x] = %c(%d), %c(%d), %c(%d)\n", mod[2].mod_start, *((char*)mod[2].mod_start), *((char*)mod[2].mod_start), *((char*)mod[2].mod_start+1), *((char*)mod[2].mod_start+1), *((char*)mod[2].mod_start+2), *((char*)mod[2].mod_start+2) ); 由图可以看出mods_count = 3,前三个字符是123,和mini-os.gz的内容完全一致。 4. 在1043行前加入 printk("Before construt_dom0\n"); 在1050行加入 printk("After construt_dom0\n"); EARLY_FAIL(""); 由图可以看出construct_dom0的作用范围。EARLY_FAIL是一个定义于setup.c中的一个macro,调用printk输出调试信息以后,无限循环调用halt()。这样可以在此处停下来,看到所有的调试信息。 ----------------------------------------- 呼----今天终于有了一点实质性的进展 :) Generated by Bo-blog 2.1.0