趣谈linux学习

学习地址

极客时间·趣谈linux

入门

自我测验

测试题1

测试题2

测试题3

测试题4

答案:

  1. A,B,C,D
  2. A,B (实模式下运行, 操作系统启动好像就只有刚开始是实模式, 流程不清楚)
  3. B ()
  4. A,B,C,D
  5. 不会

linux 学习六个坡

  • 熟练使用linux命令
  • 使用linux进行程序设计
  • 了解linux内核机制
  • 阅读linux源码
  • 实验定制linux组件
  • 落到生产实践

linux综述

电脑零件

电脑零件

外包公司业务和linux子系统对应

linux子系统

子系统:

  • 系统调用
  • 进程管理
  • 内存管理
  • 文件
  • 设备
  • 网络

基础几个系统调用

  • fork : 创建进程 ( 由 父进程 调用fork 创建 子进程, 子进程拷贝父进程 ) - 所有会有一个祖宗进程
1
2
3
4
fork 返回值:如果当前进程是子进程,就返回 0;如果当前进程是父进程,就返回子进程的进程号。
这样首先在返回值这里就有了一个区分,然后通过 if-else 语句判断,如果是父进程,还接着做原来应该做的事情;
如果是子进程,需要请求另一个系统调用execve来执行另一个程序,
这个时候,子进程和父进程就彻底分道扬镳了,也就产生了一个分支(fork)了。
  • 分配内存的系统调用,brk 和 mmap
1
2
当分配的内存数量比较小的时候,使用 brk
当分配的内存数量比较大的时候,使用 mmap,会重新划分一块区域
  • 对文件操作的系统调用 - 最重要的:open, close, create, lseek, read, write
1
2
3
4
5
6
对于已经有的文件,可以使用open打开这个文件,close关闭这个文件;
对于没有的文件,可以使用creat创建文件;
打开文件以后,可以使用lseek跳到文件的某个位置;
可以对文件的内容进行读写,读的系统调用是read,写是write

linux中 一切皆文件 - 优势: 统一操作入口

系统初始化

开放架构

  • 计算机核心: CPU
  • CPU和其他设备的连接: 总线(Bus)
  • 设备中最重要的是: 内存
  • CPU

    • 运算单元: 只管计算
    • 数据单元: 内部缓存和寄存器, 暂时存放数据和运算结果
    • 控制单元: 获得下一条指令,然后执行这条指令。 有一个 指令指针寄存器 ,它里面存放的是下一条指令在内存中的地址
  • 总线

    • 地址总线: 我想拿内存中哪个位置的数据
    • 数据总线: 真正的数据
  • 总线标准
    总线标准

8086 原理

8086原理

  • 通用寄存器 (8个 16位 ) - CPU数据单元
    • AX、BX、CX、DX、SP、BP、SI、DI。这些寄存器主要用于在计算过程中暂存数据。 (其中 AX、BX、CX、DX 可以分成两个 8 位的寄存器来使用)
  • CPU控制单元
    • IP 寄存器就是指令指针寄存器(Instruction Pointer Register),指向代码段中下一条指令的位置
    • CS 就是代码段寄存器(Code Segment Register),通过它可以找到代码在内存中的位置
    • DS 是数据段的寄存器,通过它可以找到数据在内存中的位置。
    • SS 是栈寄存器(Stack Register)。栈是程序运行中一个特殊的数据结构,数据的存取后进先出,push入栈,pop出栈

32位处理器: 80386

总线从16位变为32位, 地址位从20位变为32位

32位处理器兼容

  • 数据单元通用寄存器, 指令指针寄存器 扩展后仍然兼容
  • 但段寄存器不兼容: 原先16位总线询20位地址,是通过左移四位达到目的,段的起始地址只能是16的整除地址
    • 现在32位总线询32位地址,无所谓左移,32位4G内存都能访问到。
    • 段的起始地址放在内存的某个地方。这个地方是一个表格,表格中的一项一项是段描述符(Segment Descriptor)。这里面才是真正的段的起始地址。而段寄存器里面保存的是在这个表格中的哪一项,称为选择子(Selector)

段寄存器 寻址 不兼容咋办?

  • 模式切换: 不能无缝兼容,通过模式切换兼容
    • 实模式: 当系统刚刚启动的时候,CPU 是处于实模式的,这个时候和原来的模式是兼容的
    • 保护模式: 切换到保护模式,就能够用到 32 位 CPU 更强大的能力

从BIOS 到 bootloader

BIOS

  • BIOS
    • ROM(Read Only Memory,只读存储器)
    • 内存 RAM(Random Access Memory,随机存取存储器
1
2
3
4
5
6
7
8
9
10
主板上有部分为 ROM: 固化了一些初始化的程序,就是 BIOS (Basic Input and Output System,基本输入输出系统)

内存地址空间: 在 x86 系统中,将空间最上面的 0xF0000 到 0xFFFFF 这 64K 映射给 ROM , 到这部分地址访问的时候,会访问 ROM

当电脑刚加电的时候,会做一些重置的工作
将 CS 设置为 0xFFFF,将 IP 设置为 0x0000,所以第一条指令就会指向 0xFFFF0,正是在 ROM 的范围内。
在这里,有一个 JMP 命令会跳到 ROM 中做初始化工作的代码,于是,BIOS 开始进行初始化的工作。

BIOS: 检查硬件是否完好, 建立一个中断向量表和中断服务程序

bootloader

1
BIOS 寻找 操作系统, 操作系统在硬盘上,BIOS寻找启动盘, 一般在第一个扇区,占 512 字节,而且以 0xAA55 结束

linux系统加载流程

1
2
3
4
5
6
7
8
在Linux 里面有一个工具,叫 Grub2,  就是搞系统启动

1. grub2 第一个要安装的就是 boot.img, 由 boot.S 编译而成,一共 512 字节,正式安装到启动盘的第一个扇区。
这个扇区通常称为 MBR(Master Boot Record,主引导记录 / 扇区)。
BIOS 完成任务后,会将 boot.img 从硬盘加载到内存中的 0x7c00 来运行。
2. boot.img 字节少,做不了太多事, 主要是加载 grub的另一个镜像 core.img
首先加载 core的第一个扇区,diskboot.img, 控制权从boot到diskboot, 加载core的其他镜像, kernel是grub的内核
实模式1M空间太小, lzma_decompress会从 实模式 切换到 保护模式
  • 实模式 切换到 保护模式 工作

    1. 启用分段,就是在内存里面建立段描述符表,将寄存器里面的段寄存器变成段选择子,指向某个段描述符,这样就能实现不同进程的切换了
    2. 启动分页。能够管理的内存变大了,就需要将内存分成相等大小的块
    3. 打开 Gate A20, 8086下是20根地址总线, 到保护模式下, 打开第21根总线,开始工作
  • 总结流程

1
BIOS -》引导扇区 boot.img -》 diskboot.img -》 lzma_decompress.img 实模式切换到保护模式 -》 kernel.img 选择操作系统 -》 启动内核 

内核初始化

  1. 初始进程, 系统创建的第一个进程, 0号进程
  2. 中断门, 处理各种中断(系统调用)
  3. 内存管理模块, 调度模块
  4. 文件系统
  • 1号进程的初始化, 将运行一个用户进程。 有了 内核, 用户 的区分

    • 权限机制:x86将权限分为四个Ring
    • linux使用了 Ring0作为内核态, Ring3作为用户态
    • 系统调用执行 init文件, 内部回复寄存器,指针指向用户态, 进入用户态
    • 用户态祖先进程
  • 2号进程

    • 内核态的进程也应有一个人统一管理起来, 内核态祖先进程
    • 从内核态来看,无论是进程,还是线程,我们都可以统称为任务(Task),都使用相同的数据结构,平放在同一个链表中

系统调用

glibc 对系统调用的封装

Linux 提供了 glibc, 里面是系统调用的细节,封装成更加友好的接口。可以直接用

1
glibc 算是 办事大厅的中介

进程管理

多进程

写代码:用系统调用创建进程

  • 写代码: .h 或 .c 文件, 使用fork系统调用
  • 编译:
    • 结果: 程序的二进制文件 (格式: ELF - Executeable and Linkable Format,可执行与可链接格式 )
    • 过程:

编译过程