[Linux内核完全剖析]第七章 初始化程序(init)总结

系统初始化程序init/main.c主要功能是对系统进行初始化,并切换到用户模式下执行登录程序。
主要步骤如下:
1、系统初始化部分:

  // init/main.c void main(void)
  // 前面代码略,以下是内核进行所有方面的初始化工作。
  mem_init (main_memory_start, memory_end);
  trap_init ();                 // 陷阱门(硬件中断向量)初始化。(kernel/traps.c,181 行)
  blk_dev_init ();              // 块设备初始化。 (kernel/blk_dev/ll_rw_blk.c,157 行)
  chr_dev_init ();              // 字符设备初始化。 (kernel/chr_dev/tty_io.c,347 行)
  tty_init ();                  // tty 初始化。 (kernel/chr_dev/tty_io.c,105 行)
  time_init ();                 // 通过读取CMOS设置开机启动时间 startup_time(见76 行)。
  sched_init ();                // 调度程序初始化(加载了任务0 的tr, ldtr) (kernel/sched.c,385)
  buffer_init (buffer_memory_end);      // 缓冲管理初始化,建内存链表等。(fs/buffer.c,348)
  hd_init ();                   // 硬盘初始化。 (kernel/blk_dev/hd.c,343 行)
  floppy_init ();               // 软驱初始化。 (kernel/blk_dev/floppy.c,457 行)
  sti ();                       // 所有初始化工作都做完了,开启中断。



2、然后是切换到用户层(即idle进程),并使用fork系统调用来生成init进程,idle则循环使用pause()进入进程调度。

  // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl   // include/asm/system.h
  // 切换到用户模式运行。
  // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。
  #define move_to_user_mode() /
  __asm__ ( "movl %%esp,%%eax/n/t" /	// 保存堆栈指针esp 到eax 寄存器中。
  "pushl $0x17/n/t" /		// 首先将堆栈段选择符(SS)入栈。
  "pushl %%eax/n/t" /		// 然后将保存的堆栈指针值(esp)入栈。
  "pushfl/n/t" /		// 将标志寄存器(eflags)内容入栈。
  "pushl $0x0f/n/t" /		// 将内核代码段选择符(cs)入栈。
  "pushl $1f/n/t" /		// 将下面标号1 的偏移地址(eip)入栈。
  "iret/n" /			// 执行中断返回指令,则会跳转到下面标号1 处。
  "1:/tmovl $0x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();x17,%%eax/n/t" /	// 此时开始执行任务0,
  "movw %%ax,%%ds/n/t" /	// 初始化段寄存器指向本局部表的数据段。
  "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")
  // init/main.c void main(void)
  // 下面过程通过在堆栈中设置的参数,利用中断返回指令切换到任务0。
  move_to_user_mode ();         // 移到用户模式。 (include/asm/system.h,第1 行)
  if (!fork ())
  {                           /* we count on this going ok */
  	init ();
  }
  for(;;)
	pause();



3、fork出来的新进程调用init()函数执行shell以及登录程序

  //init/main.c
  static char *argv_rc[] = {"/bin/sh", NULL};	// 调用执行程序时参数的字符串数组。
  static char *envp_rc[] = {"HOME=/", NULL};	// 调用执行程序时的环境字符串数组。
  static char *argv[] = {"-/bin/sh", NULL};	// 作为登录shell的argv
  static char *envp[] = {"HOME=/usr/root", NULL};
  void init (void)
  {
    int pid, i;
    // 读取硬盘参数包括分区表信息并建立虚拟盘和安装根文件系统设备。
    // 对应函数是sys_setup(),在kernel/blk_drv/hd.c,71 行。
    setup ((void *) &drive_info);
    (void) open ("/dev/tty0", O_RDWR, 0);	// 返回的句柄号0 -- stdin 标准输入设备。
    (void) dup (0);		// 复制句柄,产生句柄1 号 -- stdout 标准输出设备。
    (void) dup (0);		// 复制句柄,产生句柄2 号 -- stderr 标准出错输出设备。
    printf ("%d buffers = %d bytes buffer space/n/r", NR_BUFFERS, NR_BUFFERS * BLOCK_SIZE);// 打印缓冲区块数和总字节数,每块1024 字节。
    printf ("Free mem: %d bytes/n/r", memory_end - main_memory_start);	//空闲内存字节数。
    //下面的子程序执行/etc/rc脚本来初始化用户态环境
    if (!(pid = fork ()))
    {
        close (0);
        if (open ("/etc/rc", O_RDONLY, 0))
            _exit (1);		// 如果打开文件失败,则退出(/lib/_exit.c,10)。
        execve ("/bin/sh", argv_rc, envp_rc);	// 装入/bin/sh 程序并执行。
        _exit (2);		// 若execve()执行失败则退出(出错码2,“文件或目录不存在”)。
    }
    // 父进程执行,循环等待等待子进程运行完毕。
    if (pid > 0)
        while (pid != wait (&i));
    // 循环执行并等待登录进程。
    while (1)
    {
        if ((pid = fork ()) < 0)
        {
            printf ("Fork failed in init/r/n");
	    continue;
        }
        //子进程,登录进程
        if (!pid)
        {
            close (0);
            close (1);
            close (2);// 关闭文件描述符
            setsid ();// 设置会话
            (void) open ("/dev/tty0", O_RDWR, 0);
            (void) dup (0);
            (void) dup (0);//设置文件描述符和中断关联
            _exit (execve ("/bin/sh", argv, envp));//执行登录属性的shell
        }
        //父进程,循环等待子进程退出
        while (1)
          if (pid == wait (&i))
	    break;
        printf ("/n/rchild %d died with code %04x/n/r", pid, i);
        sync ();
    }
    _exit (0);			/* NOTE! _exit, not exit() */
  }



4、系统完成了初始化过程,进入shell程序继续执行。
注意:init进程(进程1)是从idle进程(进程0)中fork出来,init继承了idle的代码、数据空间、堆栈、文件描述符等等。但由于直接从内核切换出来的idle进程没有写时复制技术,所以这两个进程共享了上述内容。为了确保数据不发生混乱,idle进程对堆栈不进行任何操作,即没有函数调用。所以在move_to_user()宏调用之后进入idle进程开始,整个idle进程使用了宏的fork(),pause()作为替换。

This entry was posted in 操作系统 and tagged . Bookmark the permalink.

发表评论

邮箱地址不会被公开。 必填项已用*标注