CPU 和设备之间靠端口交换数据,用 in 读、out 写——这是 CPU 指令集里除【搬算比跳】之外的第五类动作。
11.1 说了中间隔着驱动,这一节掀开驱动底下那一层:它到底在对什么说话。
一、CPU 和设备靠端口说话
第一章说 CPU 只会【搬、算、比、跳】四类动作——那是就程序的数据而言。
要和设备打交道,还得有第五类动作:对端口读写。
in——从端口读一个值进来。
out——把一个值写到端口去。
端口就是一个编号,CPU 认号不认名字,哪个号是谁,由硬件设计定死。
二、端口和内存不一样
两者都是【给个编号去读写】,但性质完全不同: 内存写的是位置(地址),用 movl 这类指令;端口写的是编号,用 in/out。 内存范围由地址线决定;端口范围固定是 0 到 65535 共 65536 个。 内存里存的是程序的数据;端口上是设备的状态与控制。 分开的好处是互不干扰——设备的东西不会跑到程序的数据里去。
三、端口还分宽度
按一次要传多少,端口读写分成三档: inb/outb——1 字节,用在状态位、控制位这种零星信息上。 inw/outw——2 字节,用在中等的配置值上。 inl/outl——4 字节,一次要传一段时用。 挑宽度的依据只有一条:一次要传多少。
四、为什么平时见不到它
【📋 实操路径】普通程序不能直接执行 in/out——得在内核或驱动里。 原因和第九章说的一样:这是一条【关口】,不能让谁都能随便操作硬件。 于是应用层看的永远是 API,in/out 被埋在深深的地下室。 驱动程序干的活儿,一大半就是替你在这些端口上来回读写。
五、动手 Demo:负责硬件输入输出的in指令和out指令
CPU 和设备之间靠端口交换数据,用 in 读、out 写。 这里用一个端口空间模拟那套动作。
ports = {}
def outb(port, val):
ports[port] = val & 0xFF
def inb(port):
return ports.get(port, 0xFF)
outb(0x60, 0x1E) # 往键盘端口写一个字节
print(hex(inb(0x60))) # 再读回来
print(hex(inb(0x61))) # 读一个没写过的端口
实跑输出:
--------------------------------------------------------------------
负责硬件输入输出的in指令和out指令
--------------------------------------------------------------------
**CPU 和设备之间靠【端口】交换数据**,用两条专门的指令:
in 从端口读一个值进来
out 把一个值写到端口去
端口和内存的区别在这儿:
内存 端口
--------------------------------------------------------
怎么指位置 写地址(movl) 写端口号(in/out)
编号范围 地址线决定 0 ~ 65535 共 65536 个
谁在用 程序的数据 设备的状态与控制
【📋 实操路径】普通程序不能直接执行 in/out,**得在内核或驱动里。**
这里用一个端口空间**模拟**那套动作:
outb(0x60, 0x1E) ; 往键盘端口写一个字节
inb(0x60) ; 再读回来
写 0x60 之后再读回 0x1E
读一个没写过的端口 0xFF(约定为全 1,表示【设备没准备好】)
端口还分宽度,**按要传的数据多少挑**:
指令 一次传 用在哪
------------------------------------------
inb/outb 1 字节 状态位、控制位
inw/outw 2 字节 中等配置值
inl/outl 4 字节 一次要传一大段时
**端口号记住的是【谁是谁】**——比如键盘一个、串口一个、定时器一个。
驱动程序干的活儿,一大半就是替你在这些端口上来回读写。
实测:写 0x60 之后再读回 0x1E;没写过的端口读出 0xFF(约定为全 1,表示设备没准备好)。 端口号记住的是【谁是谁】——驱动程序一大半的活儿就是在这儿来回读写。
30 秒实验
- 在纸上列一列:键盘、鼠标、串口、定时器各占一个端口号,写成一张小表。
- 想一想:为什么设备不能像文件那样【开放给所有程序随便读写】。
常见误区
- 以为端口和内存是同一回事。一个写地址、一个写端口号,空间是分开的。
- 以为应用层可以直接执行 in/out。它被限制在内核与驱动里。
自测三问(点开对答案)
1. in 和 out 指令各做什么? —— in 从端口读一个值进来,out 把一个值写到端口去。 2. 端口和内存有什么不同? —— 内存按地址访问、存程序数据;端口按编号访问(0 到 65535)、表示设备的状态与控制。 3. 为什么普通程序不能直接执行 in/out? —— 因为它是访问硬件的关口,被限制在内核和驱动里,防止任意程序操作设备。- ☐ 下一节(11.3 外部设备的中断请求)
相关笔记
- 应用程序是否与硬件有关 — 这几层是怎么叠起来的
- 外部设备的中断请求 — 设备怎么反过来通知 CPU
- CPU的处理其实很简单 — 四类动作之外的那一类
- 🔵 计算机基础 · 索引 — 硬件底层的入门课
- ⚙️ 程序是怎样跑起来的 · 索引