在 s390x 上从真实通道设备启动
s390 硬件 IPL
硬件 IPL 包含以下步骤。
在内存 0x0 构造 READ IPL CCW。 按定义,它读取磁盘柱面 0、磁道 0、记录 1 上的 IPL1。 该 CCW 带链接标志,完成后会从 0x08 获取并执行下一 CCW。
执行 0x00 的 READ IPL,将 IPL1 读入 0x00。 IPL1 共 24 字节,内容为
[psw][read ccw][tic ccw]。 数据从 0x0 开始覆盖写入,随后因原始链接标志, 自动执行 0x08 的读取 CCW 和 TIC CCW。 读取操作将 IPL2 放入内存,TIC(Transfer In Channel) 将控制转交给 IPL2 的通道程序,相当于通道程序中的跳转指令。注意:架构规定 IPL1 的 CCW 为格式 0。
执行 IPL2。 IPL1 末尾的 TIC 开始执行 IPL2,这是第二启动阶段,包含更大的通道程序。 它负责定位并加载操作系统,或加载一个从磁盘继续加载系统的小程序。 完成后,全部或部分操作系统已在内存,可交出控制。 后续所需数据由客户机操作系统自行加载。
注意:IPL2 可能向 0x0 读数据,覆盖 IPL1 的 PSW 和通道程序。 只要新的 0x0 内容包含有效 PSW,且其指令地址指向启动结束后应执行的系统代码, 就没有问题。
注意:架构规定 IPL2 的 CCW 也为格式 0。
开始执行客户机操作系统。 IPL 装入 0x0 的 PSW 应包含操作系统所需标志, 指令地址指向系统入口。通过 LPSW 加载该 PSW,转交控制。
非虚拟化环境中,用户在硬件管理控制台发起 Load,整个过程由硬件处理。 Load 在 0x0 创建特殊 READ IPL CCW 并执行,读取 IPL1。 IPL1 通道程序紧随特殊 CCW 写入,因其链接位置位而立即执行。 末尾 TIC 自动启动 IPL2。整个序列完成后,Load 从 0x0 加载 PSW。
这与 QEMU 和内核的关系
理论上,从 DASD 启动客户机只需:
在 0x0 放入带链接标志的 READ IPL CCW。
执行 0x0 通道程序。
LPSW 0x0。
但内核中的通道程序模拟缺少关键能力:不预取 CCW 数据。
启动通道程序时,通过 ORB(操作请求块)传递通道子系统参数,其中包含预取位。 置位后,vfio-ccw 内核驱动可在执行前从客户机内存读取整个通道程序。 因此,执行中再读取更多通道命令的操作无法正常工作: 新命令仅存在于客户机内存,不在内核通道子系统的副本中。 当前驱动要求所有通道程序都启用预取。 这与 IPL 的需求冲突,因为 READ IPL 完成后必须立即执行刚读入的 IPL1。
无法关闭预取也会阻止 IPL1 末尾 TIC 转到新读入的 IPL2。
此外,zipl 等启动加载程序的 IPL2,也会在从磁盘读取后立即跳到另一段通道程序, 同样需要处理。
QEMU 的处理方式
由于必须使用预取,不能直接采用前述简单流程,改为:
在 0x0 放 READ IPL,但关闭链接标志。
执行 0x0 的 READ IPL。
此时 IPL1 的 PSW 位于 0x0,通道程序位于 0x08。
编写自定义通道程序,先定位 IPL2 记录,再执行 IPL1 中的 READ 和 TIC。 正常硬件在读取 IPL1 后自动定位到下一个 IPL2 记录,无需额外寻道。 但这里不是同一个通道程序读取两者,因此必须手动定位。
取得 IPL1 TIC 的目标地址,即 IPL2 通道程序起点。
此时 IPL2 已加载到已知地址。
在步骤 4 的地址执行 IPL2。
程序可能动态变化,因此使用专用算法检测 READ 紧接 TIC 的情况, 关闭 READ 的链接位,切断 CCW 链。 内核/硬件返回 QEMU BIOS 后,立即再次启动子通道执行剩余 TIC, 使从 TIC 开始的整个程序及所需数据重新获取,绕开预取限制。
此时操作系统代码已加载到客户机内存,0x0 的 PSW 指向其入口。
LPSW 0x0。
将控制转交给客户机操作系统,启动完成。