Linux0.11 系统调用进程创建与执行(九)(上)

简介: Linux0.11 系统调用进程创建与执行(九)

前提回顾

    Linux 系统经历 BIOSbootsect.s、setup.s、head.s 一系列执行后,    其从实模式切换到了 32 位保护模式,此时即将运行 init/main.c 中的 main 函数。

内存分布

此时其内存分布如下:

堆栈信息

堆栈信息如下图:

寄存器信息

段选择符

通用寄存器

task[0] 信息

struct task_struct {
  // ...
  
    /* 本任务的局部表描述符。 0 空, 1 代码段 cs, 2 数据段和堆栈段 ds&ss */
  struct desc_struct ldt[3];
    /* 本进程的任务状态段信息结构 */
  struct tss_struct tss;
};

task[0] 初始化:

#define INIT_TASK \
/* state etc */ { 0,15,15, \
/* signals */ 0,{{},},0, \
/* ec,brk... */ 0,0,0,0,0,0, \
/* pid etc.. */ 0,-1,0,0,0, \
/* uid etc */ 0,0,0,0,0,0, \
/* alarm */ 0,0,0,0,0,0, \
/* math */  0, \
/* fs info */ -1,0022,NULL,NULL,NULL,0, \
/* filp */  {NULL,}, \
  { \
    {0,0}, \
/* ldt */ {0x9f,0xc0fa00}, \
    {0x9f,0xc0f200}, \
  }, \
/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
   0,0,0,0,0,0,0,0, \
   0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
   _LDT(0),0x80000000, \
    {} \
  }, \
}
ldt

tss


一、环境初始化

void main(void) /* This really IS void, no error here. */
{               /* The startup routine assumes (well, ...) this */
                /*
                 * Interrupts are still disabled. Do necessary setups, then
                 * enable them
                 */

  ROOT_DEV = ORIG_ROOT_DEV;
  drive_info = DRIVE_INFO;
  memory_end = (1 << 20) + (EXT_MEM_K << 10);
  memory_end &= 0xfffff000;
  if (memory_end > 16 * 1024 * 1024)
    memory_end = 16 * 1024 * 1024;
  if (memory_end > 12 * 1024 * 1024)
    buffer_memory_end = 4 * 1024 * 1024;
  else if (memory_end > 6 * 1024 * 1024)
    buffer_memory_end = 2 * 1024 * 1024;
  else
    buffer_memory_end = 1 * 1024 * 1024;
  main_memory_start = buffer_memory_end;
#ifdef RAMDISK
  main_memory_start += rd_init(main_memory_start, RAMDISK * 1024);
#endif
  mem_init(main_memory_start, memory_end);
  trap_init();
  blk_dev_init();
  chr_dev_init();
  tty_init();
  time_init();
  sched_init();
  buffer_init(buffer_memory_end);
  hd_init();
  floppy_init();
  sti();
  move_to_user_mode();
  if (!fork()) { /* we count on this going ok */
    init();
  }
  /*
   *   NOTE!!   For any other task 'pause()' would mean we have to get a
   * signal to awaken, but task0 is the sole exception (see 'schedule()')
   * as task 0 gets activated at every idle moment (when no other tasks
   * can run). For task0 'pause()' just means we go check if some other
   * task can run, and if not we return here.
   */
  for (;;)
    pause();
}


    代码执行到 move_to_user_mode 函数之前,其进行了一系列初始化操作。跟踪发现除了通用寄存器发生变化外,段寄存器,task[0]ldttss 都未发生变化。

以下为通用寄存器信息:


    执行完 move_to_user_mode 函数后,程序由内核态进入用户态(任务 0 的用户态)。

二、move_to_user_mode

move_to_user_mode 函数把进程 0 由内核态转成用户态。其代码如下:

#define move_to_user_mode() \   // 模仿中断硬件压栈,顺序是 ss、esp、eflags、cs、eip
__asm__ ("movl %%esp,%%eax\n\t" \ // 保存堆栈指针 esp 到 eax 寄存器中
  "pushl $0x17\n\t" \       // 堆栈段选择符 ss 入栈, 0x17 即二进制的 10111(特权级3、LDT、数据段)
  "pushl %%eax\n\t" \       // 堆栈指针 esp 入栈
  "pushfl\n\t" \          // 标志进村器 eflags 入栈
  "pushl $0x0f\n\t" \       // Task0 代码段选择符 cs 入栈, 0x0f 即 111 (特权级3、LDT、代码段)
  "pushl $1f\n\t" \       // 将下面标号 1 的偏移地址 eip 入栈
  "iret\n" \            // 出栈恢复现场,翻转特权级从 0 到 3,中断返回,会跳转到下面标号 1处
  "1:\tmovl $0x17,%%eax\n\t" \  // 此时开始执行进程 0 。
  "movw %%ax,%%ds\n\t" \      // 初始化段寄存器指向 task0 的局部表的数据段
  "movw %%ax,%%es\n\t" \      // 下面的代码使 es、fs、gs 与 ds 一致
  "movw %%ax,%%fs\n\t" \
  "movw %%ax,%%gs" \
  :::"ax")

1、寄存器

此时寄存器的信息如下:

ldt:

tss 未发生变化

2、分析

typedef struct desc_struct {
  unsigned long a,b;
} desc_table[256];

以下为 GDT、LDT、TSS 间的关系:

值的形式为:b:a,其位于地址 0x5cb8 处。

0 1 2 3 4 5
NULL 内核CS 内核DS NULL TSS0 LDT0
0:0 C09A00:FFF C09300:FFF 0:0 8B01:F4480068 8201:F4300068
6 7 8 9
TSS1 LDT1 TSS2 LDT2
0:0 0:0 0:0 0:0

2.1 段选择符

段选择符结构如下:

2.2 段描述符


2.3 Task0 处于用户态
CS

    此时段寄存器 CS0x0F。指定了 LDT 中具有 RPL=3 的段 1,其索引字段值是 1,TI 位是 1,指定 LDT 表。其指向Task0的局部描述符,其值为:C0FA00:0x9F

   备注:GDT 中第 5 个值 LDT0 存储了 LDT 描述符地址,其值为:8201:F4300068,其段基址为 0x1F430,段限长为 104 个字节。段基址正好指向 task[0] 中成员变量 ldt 的地址。而 task[0].ldt[1] 为 LDT 描述符,其值正是上文说的 C0FA00:0x9F

其他段寄存器 SS、DS、ES、FS、GS

    此时其他段寄存器 SSDS、ES、FS、GS 值为 0x17。指定了 LDT 中具有 RPL=3 的段 2,其索引字段值是 2,TI 位是 1,指定 LDT 表。其指向Task0的局部描述符,其值为:C0F300:0x9F

   备注:GDT 中第 4 个值 TSS0 存储了 TSS 描述符地址,其值为:8B01:F4480068,其段基址为 0x1F448,段限长为 104 个字节。段基址正好指向 task[0] 中成员变量 tss 的地址。而 task[0].tss 为 TSS 描述符,其值正是上文说的 C0F300:0x9F


2.4 Task0 处于内核态
CS

    此时段寄存器 CS0x08。其指定了 GDT 中具有 RPL=0 的段 1,其索引字段值是 1,TI 位是 0,指定 GDT 表。其指向的描述符值为:0xC09A00:FFF

其他段寄存器 SS、DS、ES、FS、GS

    此时其他段寄存器 SSDS、ES、FS、GS 值为 0x10。其指定了 GDT 中具有 RPL=0 的段 2,其索引字段值是 2,TI 位是 0,指定 GDT 表。其指向的描述符值为:0xC09300:FFF


Linux0.11 系统调用进程创建与执行(九)(下):https://developer.aliyun.com/article/1597313

目录
相关文章
|
6月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
249 67
|
5月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
135 16
|
5月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
107 20
|
4月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
83 0
|
4月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
114 0
|
4月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
80 0
|
4月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
81 0
|
7月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
239 4
|
7月前
|
Linux Shell
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
346 5
|
7月前
|
Linux 应用服务中间件 nginx
Linux 进程管理基础
Linux 进程是操作系统中运行程序的实例,彼此隔离以确保安全性和稳定性。常用命令查看和管理进程:`ps` 显示当前终端会话相关进程;`ps aux` 和 `ps -ef` 显示所有进程信息;`ps -u username` 查看特定用户进程;`ps -e | grep &lt;进程名&gt;` 查找特定进程;`ps -p &lt;PID&gt;` 查看指定 PID 的进程详情。终止进程可用 `kill &lt;PID&gt;` 或 `pkill &lt;进程名&gt;`,强制终止加 `-9` 选项。
100 3