先来想象这么个画面:
你新装好一台电脑,插上电源,按下开机键。
机箱里灯一亮,风扇一转,屏幕一黑……然后慢慢出现 logo,几秒钟之后,进了桌面。
你大概只会想一句:“开机了。”
但从机器眼里看,这几秒钟简直是惊心动魄的“夺权现场”——
一开始是硬件在当老大,
几秒钟后,操作系统彻底接管了整个机器,
从此,所有程序都得听它的。
今天这一篇,就用大白话聊清楚:
操作系统上来干的第一件大事:接管硬件,
它是怎么一步步把 CPU、内存、设备统统拿在手里的。
你可以把这篇当成“操作系统夺权记”。
一、开机那一刻:操作系统其实还没上场
先把事实说清楚:
你按下电源的那一瞬间,操作系统根本还没跑起来。
那这会儿是谁在干活?
答案是:主板上的固件——BIOS 或 UEFI。
1.1 BIOS / UEFI 是啥玩意?
你可以把它想象成:
主板自带的一个“小系统”,专门负责开机自检 + 找到操作系统。
它是写死在主板芯片里的,不会轻易被弄没。
作用主要有两个:
做硬件自检(POST)
- 看内存条插好了没
- 看键盘、显卡等有没有问题
- 有大问题就“滴滴滴”报警、停在黑屏上
启动操作系统
- 在硬盘、U 盘、网络等设备上找“引导程序”(bootloader)
- 把它加载到内存,转交控制权
这时候,电脑里还是硬件当爹,BIOS/UEFI 当老大,根本轮不到 Windows/Linux 上场。
1.2 CPU 开机后干的第一件事
CPU 一通电,会从一个固定地址开始执行代码。
这个地址上的内容就是 BIOS/UEFI 的启动代码。
你可以简单理解成:
CPU:我醒了,先看看主板留给我的“开机指令集”,按它说的做。
BIOS/UEFI 执行完基本自检后,就开始干一件关键事:
“把真正的大老板——操作系统——找出来,叫起来。”
二、引导程序:操作系统的“接头人”
你可以理解为:
BIOS/UEFI 不懂什么是“Windows/Linux”,它只知道去硬盘头上某个固定地方看看有没有“启动代码”。
这段启动代码,就是引导程序(bootloader)。
2.1 Bootloader 干嘛用?
一句话:
Bootloader 是“接力棒中转站”:
负责把操作系统内核从磁盘搬进内存,并把 CPU 控制权交给它。
在 PC 上,比如:
- 你装了 Windows → 有 Windows 的 bootloader
- 你装了 Linux → 有 GRUB / systemd-boot 等 bootloader
它们的活儿通常是:
- 从硬盘的特定位置(MBR 或 EFI 分区)被 BIOS/UEFI 加载进内存执行;
- 了解硬盘上有几个系统(多系统启动菜单就是它做的);
- 根据配置选一个系统,把它的“内核文件”读入内存;
- 准备好内核启动需要的数据(参数、内存布局信息等);
- 跳转到内核入口地址:
- 也就是“操作系统,轮到你了!”
2.2 为什么不让 BIOS 直接加载操作系统?
原因很现实:
BIOS/UEFI 功能有限、厂商各家自定义多;
操作系统种类太多,不能要求 BIOS 支持所有具体系统的细节;
把“启动 OS”这件事交给 bootloader,灵活性更强:
- 可以给你“选择启动哪个系统”的菜单
- 可以支持加密磁盘、特殊启动参数等
- 可以更方便地更新(换个 bootloader 不用换主板)
所以启动链大致是:
硬件 → BIOS/UEFI → bootloader → OS 内核
这才算是把“舞台”搭好了,下面轮到操作系统上场表演:接管硬件。
三、内核登场:操作系统“正式上位”
bootloader 把操作系统内核文件(比如vmlinuz、ntoskrnl.exe)读进内存后,
会把 CPU 的控制权交给内核的入口函数。
从这一刻起,可以说:
操作系统真正开始跑了。
那内核第一件事干什么?
用一句话概括:
把这台裸机器“接管”到一个可控状态。
具体可以拆成几步来看:
- 接管和配置 CPU 模式
- 建立基础的内存管理机制
- 初始化中断系统
- 识别和初始化各种设备(通过驱动)
- 启动第一个用户态进程
下面一块块说。
四、接管 CPU:从“傻模式”切到“高级模式”
CPU 一开始是以比较原始的模式启动的,比如 x86 架构的一开始是在 16 位实模式里。
这个模式下:
- 能访问的内存有限(比如 1MB)
- 没有高级的内存保护、分页机制
- 不能直接支持现代操作系统需要的那些花活(虚拟内存、多任务等)
内核接手后干的第一件大事,就是:
把 CPU 从“原始模式”切换到“现代高级模式”(保护模式 / 长模式)。
4.1 CPU 模式切换:从“裸奔”到“穿盔甲”
在 x86 上,大致顺序是:
- 启动时处于 16 位实模式(古早 DOS 时代那套);
- 切换到 32 位保护模式:
- 引入段表、页表、特权级(用户态/内核态)等概念;
- 在 64 位系统上,还会切到 64 位长模式:
- 支持更大内存地址空间,更多寄存器等。
具体细节很硬核,但你只要理解这点:
操作系统负责把 CPU 调整到“我最舒服的工作状态”,
然后以后所有程序都在这种状态下跑。
这时候,CPU 有了特权级区分:
- 内核态(ring 0):操作系统内核运行的位置,权限最大;
- 用户态(ring 3):普通程序运行位置,权限受限。
以后你写的程序都跑在用户态,
想干特权操作,只能通过“系统调用”让内核代劳。
这,就是接管 CPU 的核心意义:
- 让程序不能乱搞硬件
- 有了区分权限的能力
五、接管内存:从“一大坨物理内存”到“虚拟内存世界”
光有 CPU 不够,还要把内存搞明白。
刚开机的内存状态大概是:
BIOS/UEFI + bootloader + 内核 本身占了一块,剩下全是“原始裸内存”。
操作系统要把这“裸内存”变成:
- 一部分自己用(内核空间)
- 一部分给将来创建的进程用(用户空间)
- 并且还要支持虚拟内存(分页机制)
5.1 建立页表:给虚拟内存铺路
内核启动时会做一件很重要的事:
为自己先建立一套基本的页表(page table)。
作用是:
- 把自己的代码、数据等映射到一些虚拟地址上;
- 把硬件设备的一些地址空间(内存映射 I/O)也配置好;
- 给内存管理子系统打好基础。
从这一刻开始:
- CPU 通过 MMU 将虚拟地址翻译成物理地址;
- 内核可以开始玩“虚拟内存”的那套把戏。
你可以理解为:
内核先给自己“安家”,
把“内核地盘”划出来,
然后才有底气去给别的进程分房子。
六、接管中断:硬件有事先跟我说!
电脑里不仅有 CPU 在算,还有很多外设自己也在干活:
- 键盘:有人按键了
- 鼠标:移动/点击了
- 磁盘:读写完成了
- 网卡:收到了网络数据包
这些事件是异步发生的,CPU 不可能每毫秒去问一遍:“你有事吗?”——那太浪费。
现实做法是:
设备有事时,主动“打断”CPU,发一个中断(interrupt)。
操作系统接管硬件的一个关键步骤,就是:
- 设置中断向量表 / 中断描述符表(IDT):
- 告诉 CPU:
- 某种中断发生时,去哪里执行处理代码。
- 告诉 CPU:
- 为各种设备注册中断处理程序:
- 键盘中断 → 调用键盘驱动代码
- 磁盘中断 → 调用磁盘驱动,唤醒等 I/O 的进程
- 定时器中断 → 用来做时间片轮转调度
从此以后,整个机器里的“消息通道”像这样运转:
- 设备有事 → 发中断 → CPU 暂停当前进程 → 跳到内核中断处理程序
- 内核处理完 → 恢复现场 → 继续让刚才那个进程跑
这就是操作系统“接管中断”的意义:
所有硬件给 CPU 的“通知”,都统一先交给 OS 内核处理。
内核再决定:唤醒哪个进程、给谁发信号、怎么更新状态。
七、接管设备:驱动让乱七八糟的硬件说同一种“话”
电脑上各种设备——硬盘、显卡、网卡、USB、音频设备……
每家厂商的接口、寄存器都长得不一样,
要让操作系统管理它们,就要有一个“翻译层”:驱动程序(Driver)。
7.1 操作系统怎么“认设备”?
内核启动后会做一件“大扫除”:
扫描各种总线(PCI、USB 等),看看挂了哪些设备。
它会:
- 读取硬件设备的厂商 ID、设备 ID;
- 根据这些信息,找到系统里对应的驱动模块;
- 把驱动加载进内存,并调用驱动的初始化函数。
驱动的初始化会干什么?
- 告诉内核:“我可以处理这个设备的请求”;
- 注册中断处理函数;
- 为设备创建对应的“设备文件”或接口(比如
/dev/sda、/dev/ttyS0等)。
从这一刻起:
各种稀奇古怪的硬件
= 在操作系统眼里变成了一堆统一管理的“设备对象”。
上层的应用不需要知道某品牌网卡内部寄存器长啥样,
它只需要跟 OS 提供的“套接字接口(socket)”打交道——
剩下的,内核 + 驱动搞定。
7.2 “一切皆文件”:统一接口的好处
许多 Unix/Linux 系统坚持一个哲学:一切皆文件。
意思是:
- 磁盘是文件
- 串口是文件
- 管道是文件
- 设备也是文件(
/dev下那些)
都可以用相同的接口访问:
open();read();write();close();比如你给串口发数据、给文件写日志、给某个设备写控制命令,
在代码层面可能都是write(fd, buf, len):
- 后续具体在哪儿写、怎么写,
是 OS 通过“文件系统层 + 驱动层”帮你翻译好的。
这就是“统一抽象”的威力。
八、接管时间:定时器中断 + 时钟,让一切有“时间感”
操作系统还必须接管一件重要资源:时间。
你会发现很多操作都涉及时间:
- 线程睡眠几秒
sleep(3); - 进程超时;
- 定时任务(cron、计划任务);
- 统计 CPU 使用时间、系统运行时间等。
这些都离不开一个基础机制:定时器中断。
8.1 定时器中断是怎么用的?
内核在初始化时会配置硬件定时器(或 APIC 等):
- 比如每隔 1ms/10ms 触发一次“时钟中断”。
每次时钟中断发生时:
- CPU 暂停当前进程,跳到内核的时钟中断处理程序;
- 内核更新系统时钟:
- 当前时间 +1 tick
- 进程运行时间累加等;
- 检查是否有定时事件到期:
- 某个线程 sleep 时间到了 → 唤醒它;
- 检查当前进程的时间片是否用完:
- 用完了就触发一次调度,切换到下一个进程。
也就是说:时间片轮转调度也是靠这个定时器中断实现的。
如果没有操作系统接管时间:
- 没人定期打断 CPU,
- 那一个进程一旦开始执行就可能死赖着不松手,
- 你开的其他程序基本没机会跑。
九、接管“控制权”:从“裸机”到“多进程世界”
到目前为止,内核已经干了这些“接管动作”:
- 控制 CPU 的模式和特权级
- 建好了自己的内存映射和页表
- 配置了中断系统
- 初始化了设备和驱动
- 接管了定时器(时间)
接下来,它要完成最后一步关键动作:
创建第一个用户态进程,
把控制权从“裸内核”推进到“多进程世界”。
9.1 第一个进程:万物之源
在 Linux 里,内核会启动一个非常重要的进程:pid = 1,传统上叫init,现在多用systemd之类。
它负责:
- 启动各种系统服务(网络服务、日志服务、图形界面服务等);
- 最终给你一个登录界面 / 桌面环境 / shell。
而所有后来的用户进程:
- 浏览器、编辑器、数据库、你写的程序……
- 都是直接或间接由 pid=1 这个“祖宗进程” fork/exec 出来的。
在 Windows 里也有类似的“系统进程”“服务进程”,只是名字和体系不同。
从这一步开始,整个系统就变成了:
多进程 + 多线程并发执行,
各自跑在用户态,
通过系统调用来请求 OS 做事,
OS 控制调度、内存、设备、文件,一切都在它手里。
到此,操作系统正式完成了“接管硬件”的阶段性任务,
从一个冷冰冰的电路板 + 磁盘,变成了一个“有秩序的多任务环境”。
十、把“接管硬件”这件事,用一句话串起来
我们最后用一段压缩版流程,把整件事情复盘一下:
通电启动:
硬件上电,CPU 从固定地址执行 BIOS/UEFI 的启动代码。BIOS/UEFI 自检 + 寻找启动设备:
检查内存、外设是否可用;
找到硬盘/U盘上的 bootloader,把它载入内存并运行。bootloader 载入操作系统内核:
根据配置选定一个 OS,
把内核文件读入内存,把控制权交给内核入口。内核初始化,接管 CPU:
切换到合适的工作模式(32/64 位保护模式 / 长模式);
设置特权级(用户态/内核态)的规则。内核初始化内存管理:
搭建页表,划分内核空间和用户空间,
为将来的虚拟内存做好基础。内核初始化中断系统:
设置中断向量表/IDT;
注册各种中断处理程序(时钟、设备等)。内核识别并初始化设备:
扫描总线,加载驱动,建立设备对象;
把杂乱的硬件统一封装成标准接口(文件/设备节点/抽象 API)。内核接管时钟和定时器:
注册时钟中断,用来更新系统时间和进行调度。启动第一个用户进程:
启动各种系统服务,最后给你提供 shell/图形桌面。从此以后:
- 所有用户程序都跑在用户态;
- 想动硬件,只能通过系统调用让内核代劳;
- 内核使用中断、调度、内存管理、驱动等机制,
统筹这台机器上的所有资源。
你可以这样记住:
“接管硬件”这件事,就是操作系统从无到有地,把一台空机器
变成一个有规矩、有秩序、可多任务的“数字世界”的过程。
等你再学操作系统后面的章节——进程管理、调度、内存管理、文件系统、设备驱动——
你就可以时不时问自己一句:
“这个东西,属于操作系统接管哪个硬件资源的后续玩法?”
有了今天这条“接管硬件的时间线”在脑子里,
你就不会把操作系统当成一坨难懂的黑盒子,
而是一个你大概看懂了“上位过程”和“掌权方式”的大管家。