ReactOS 图形系统分析(2):视频端口驱动 videoprt.sys
1. 概述
videoprt.sys 是 ReactOS 的 视频端口驱动(Video Port Driver) ,源代码位于 win32ss/drivers/videoprt/。它是 Windows NT 视频驱动架构(NT 5.x/XP)中承上启下的核心组件:
- 向下 :为 MiniPort 驱动提供全部
VideoPort*服务函数(约 150 个导出) - 向上:为显示驱动 DDI(framebuf.dll)提供 IRP/IOCTL 服务
- 横向:管理 INT 10 BIOS 调用(x86 模拟器 / V86 模式)、PnP 设备管理、子设备(显示器)枚举
在上一份分析(VirtualBox虚拟机显示驱动分析.md)中已确认,VirtualBox 虚拟机实际加载了该驱动(videoprt.sys),与 vgapnp.sys(VBE miniport)、framebuf.dll(显示驱动 DDI)构成完整显示栈。
1.1 模块文件构成
| 文件 | 功能 |
|---|---|
| videoprt.c(file:///d:/reactos/win32ss/drivers/videoprt/videoprt.c) | 主实现:VideoPortInitialize、适配器检测、设备对象创建、子设备枚举、杂项服务 |
| videoprt.h(file:///d:/reactos/win32ss/drivers/videoprt/videoprt.h) | 头文件:核心数据结构、函数声明 |
| dispatch.c(file:///d:/reactos/win32ss/drivers/videoprt/dispatch.c) | IRP 分发:Open/Close/DeviceControl/PnP/Power、INBV 显示所有权 |
| int10.c(file:///d:/reactos/win32ss/drivers/videoprt/int10.c) | INT 10 BIOS 调用服务(x86 模拟器 + V86 模式双实现) |
| resource.c(file:///d:/reactos/win32ss/drivers/videoprt/resource.c) | 内存映射、访问范围、池分配、总线读写 |
| registry.c(file:///d:/reactos/win32ss/drivers/videoprt/registry.c) | 注册表路径创建、设备设置键复制 |
| services.c(file:///d:/reactos/win32ss/drivers/videoprt/services.c) | VideoPortQueryServices 接口查询(INT10/AGP) |
| interrupt.c(file:///d:/reactos/win32ss/drivers/videoprt/interrupt.c) | 中断设置 |
| timer.c(file:///d:/reactos/win32ss/drivers/videoprt/timer.c) | 定时器服务 |
| event.c(file:///d:/reactos/win32ss/drivers/videoprt/event.c) | 事件服务 |
| spinlock.c(file:///d:/reactos/win32ss/drivers/videoprt/spinlock.c) | 自旋锁服务 |
| dma.c(file:///d:/reactos/win32ss/drivers/videoprt/dma.c) | DMA 服务 |
| ddc.c(file:///d:/reactos/win32ss/drivers/videoprt/ddc.c) | DDC 显示器数据通道辅助 |
| child.c(file:///d:/reactos/win32ss/drivers/videoprt/child.c) | 子设备相关服务 |
| agp.c(file:///d:/reactos/win32ss/drivers/videoprt/agp.c) | AGP 总线接口 |
| stubs.c(file:///d:/reactos/win32ss/drivers/videoprt/stubs.c) | 未实现函数的桩 |
| guid.c(file:///d:/reactos/win32ss/drivers/videoprt/guid.c) | GUID 定义 |
| videoprt.spec(file:///d:/reactos/win32ss/drivers/videoprt/videoprt.spec) | 导出定义(约 150 个 VideoPort* 函数) |
| CMakeLists.txt(file:///d:/reactos/win32ss/drivers/videoprt/CMakeLists.txt) | 构建配置(kernelmodedriver,导入 ntoskrnl+hal) |
2. 架构定位与驱动模型
2.1 Windows 视频驱动分层
#mermaid-svg-yr8TWfGEUcSjSjCF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yr8TWfGEUcSjSjCF .error-icon{fill:#552222;}#mermaid-svg-yr8TWfGEUcSjSjCF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yr8TWfGEUcSjSjCF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yr8TWfGEUcSjSjCF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yr8TWfGEUcSjSjCF .marker.cross{stroke:#333333;}#mermaid-svg-yr8TWfGEUcSjSjCF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yr8TWfGEUcSjSjCF p{margin:0;}#mermaid-svg-yr8TWfGEUcSjSjCF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yr8TWfGEUcSjSjCF .cluster-label text{fill:#333;}#mermaid-svg-yr8TWfGEUcSjSjCF .cluster-label span{color:#333;}#mermaid-svg-yr8TWfGEUcSjSjCF .cluster-label span p{background-color:transparent;}#mermaid-svg-yr8TWfGEUcSjSjCF .label text,#mermaid-svg-yr8TWfGEUcSjSjCF span{fill:#333;color:#333;}#mermaid-svg-yr8TWfGEUcSjSjCF .node rect,#mermaid-svg-yr8TWfGEUcSjSjCF .node circle,#mermaid-svg-yr8TWfGEUcSjSjCF .node ellipse,#mermaid-svg-yr8TWfGEUcSjSjCF .node polygon,#mermaid-svg-yr8TWfGEUcSjSjCF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yr8TWfGEUcSjSjCF .rough-node .label text,#mermaid-svg-yr8TWfGEUcSjSjCF .node .label text,#mermaid-svg-yr8TWfGEUcSjSjCF .image-shape .label,#mermaid-svg-yr8TWfGEUcSjSjCF .icon-shape .label{text-anchor:middle;}#mermaid-svg-yr8TWfGEUcSjSjCF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yr8TWfGEUcSjSjCF .rough-node .label,#mermaid-svg-yr8TWfGEUcSjSjCF .node .label,#mermaid-svg-yr8TWfGEUcSjSjCF .image-shape .label,#mermaid-svg-yr8TWfGEUcSjSjCF .icon-shape .label{text-align:center;}#mermaid-svg-yr8TWfGEUcSjSjCF .node.clickable{cursor:pointer;}#mermaid-svg-yr8TWfGEUcSjSjCF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yr8TWfGEUcSjSjCF .arrowheadPath{fill:#333333;}#mermaid-svg-yr8TWfGEUcSjSjCF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yr8TWfGEUcSjSjCF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yr8TWfGEUcSjSjCF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yr8TWfGEUcSjSjCF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yr8TWfGEUcSjSjCF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yr8TWfGEUcSjSjCF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yr8TWfGEUcSjSjCF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yr8TWfGEUcSjSjCF .cluster text{fill:#333;}#mermaid-svg-yr8TWfGEUcSjSjCF .cluster span{color:#333;}#mermaid-svg-yr8TWfGEUcSjSjCF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yr8TWfGEUcSjSjCF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yr8TWfGEUcSjSjCF rect.text{fill:none;stroke-width:0;}#mermaid-svg-yr8TWfGEUcSjSjCF .icon-shape,#mermaid-svg-yr8TWfGEUcSjSjCF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yr8TWfGEUcSjSjCF .icon-shape p,#mermaid-svg-yr8TWfGEUcSjSjCF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yr8TWfGEUcSjSjCF .icon-shape .label rect,#mermaid-svg-yr8TWfGEUcSjSjCF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yr8TWfGEUcSjSjCF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yr8TWfGEUcSjSjCF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yr8TWfGEUcSjSjCF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 硬件层
MiniPort 驱动层
视频端口驱动层 (videoprt.sys) ← 本分析对象
显示驱动层 (DDI)
用户模式
EngDeviceIoControl
打开 \\Device\\Video0
转发 VRP
被调用
INT 10 调用
VideoPort* 服务
VideoPortQueryServices
获取 INT10 接口
PNP IRP
同样通过 VideoPort*
win32k.sys 内核 GDI
加载显示驱动 DDI
framebuf.dll
DrvEnablePDEV / DrvBitBlt
IRP 分发
IRP_MJ_DEVICE_CONTROL
VideoPort* 服务函数
(150+ 导出)
INT 10 BIOS 服务
(模拟器/V86)
PnP 设备管理
/Device/VideoN
vgapnp.sys (VBE)
HwFindAdapter/HwStartIO
bochsmp.sys / vgamp.sys 等
VBE BIOS (INT 10)
显卡硬件
2.2 MiniPort + Port 驱动的协作模式
视频端口驱动的核心设计思想:MiniPort 驱动不直接操作硬件 ,所有硬件操作都通过 VideoPort* 服务函数委托给端口驱动完成。
| 服务类别 | 代表函数 | 功能 |
|---|---|---|
| 初始化 | VideoPortInitialize |
MiniPort 在 DriverEntry 中调用,注册回调表 |
| 内存映射 | VideoPortMapMemory / VideoPortUnmapMemory |
映射帧缓冲/设备内存 |
| 端口/寄存器 | VideoPortReadPortUchar ~ VideoPortWriteRegisterUlong |
I/O 端口与内存映射寄存器访问 |
| 内存操作 | VideoPortAllocatePool / VideoPortZeroMemory 等 |
池分配、内存复制 |
| 同步 | VideoPortAcquireSpinLock / VideoPortSynchronizeExecution |
自旋锁、同步执行 |
| 中断 | VideoPortEnableInterrupt / VideoPortDisableInterrupt |
中断控制 |
| 定时器 | VideoPortStartTimer / VideoPortStopTimer |
定时器 |
| DMA | VideoPortStartDma / VideoPortCompleteDma 等 |
DMA 传输 |
| BIOS | VideoPortInt10 / VideoPortQueryServices |
INT 10 调用、接口查询 |
| 注册表 | VideoPortGetRegistryParameters / VideoPortSetRegistryParameters |
注册表读写 |
| 子设备 | VideoPortEnumerateChildren |
显示器枚举 |
| 诊断 | VideoPortLogError / VideoPortDebugPrint |
错误记录、调试输出 |
3. 核心数据结构
3.1 VIDEO_PORT_DRIVER_EXTENSION --- 驱动级扩展(每个 MiniPort 一份)
c
typedef struct _VIDEO_PORT_DRIVER_EXTENSION
{
VIDEO_HW_INITIALIZATION_DATA InitializationData; // MiniPort 注册的 Hw 回调表
PVOID HwContext; // MiniPort 私有上下文
UNICODE_STRING RegistryPath; // 驱动的注册表路径(Services\xxx)
} VIDEO_PORT_DRIVER_EXTENSION, *PVIDEO_PORT_DRIVER_EXTENSION;
InitializationData 保存 MiniPort 在 DriverEntry 中通过 VIDEO_HW_INITIALIZATION_DATA 注册的所有回调:
HwFindAdapter、HwInitialize、HwStartIO、HwResetHw、HwGetPowerState、HwSetPowerState、HwGetVideoChildDescriptor 等。
3.2 VIDEO_PORT_DEVICE_EXTENSION --- 设备级扩展(每个适配器一份)
c
typedef struct _VIDEO_PORT_DEVICE_EXTENSTION
{
VIDEO_PORT_COMMON_EXTENSION Common; // Fdo 标志
ULONG DeviceNumber; // 设备编号(\Device\VideoN 的 N)
PDRIVER_OBJECT DriverObject;
PDEVICE_OBJECT PhysicalDeviceObject; // PDO(来自 PnP)
PDEVICE_OBJECT FunctionalDeviceObject; // FDO(自己创建的)
PDEVICE_OBJECT NextDeviceObject; // 设备栈中下一层
UNICODE_STRING RegistryPath; // 传统注册表路径
UNICODE_STRING NewRegistryPath; // 新格式注册表路径
PKINTERRUPT InterruptObject; // 中断对象
KSPIN_LOCK InterruptSpinLock;
PCM_RESOURCE_LIST AllocatedResources; // PnP 分配的资源
ULONG InterruptVector;
ULONG InterruptLevel;
BOOLEAN InterruptShared;
INTERFACE_TYPE AdapterInterfaceType; // 总线类型(PCI 等)
ULONG SystemIoBusNumber;
ULONG SystemIoSlotNumber;
LIST_ENTRY AddressMappingListHead; // 地址映射链表
KDPC DpcObject; // DPC 对象(VideoPortQueueDpc 用)
VIDEO_PORT_DRIVER_EXTENSION *DriverExtension; // 反向引用驱动扩展
ULONG DeviceOpened; // 打开计数
AGP_BUS_INTERFACE_STANDARD AgpInterface; // AGP 接口
KMUTEX DeviceLock; // 设备锁(Acquire/Release 用)
LIST_ENTRY DmaAdapterList, ChildDeviceList;// DMA 适配器列表、子设备列表
LIST_ENTRY HwResetListEntry; // 可复位适配器链表节点
ULONG SessionId; // 会话 ID(多会话)
USHORT AdapterNumber;
USHORT DisplayNumber;
ULONG NumberOfSecondaryDisplays;
BOOLEAN IsLegacyDevice; // 是否为传统(非 PnP)设备
BOOLEAN IsLegacyDetect;
BOOLEAN IsVgaDriver;
// ... MiniPortDeviceExtension 紧随其后
} VIDEO_PORT_DEVICE_EXTENSION, *PVIDEO_PORT_DEVICE_EXTENSION;
关键点: 设备对象创建时,IoCreateDevice 的扩展大小 = sizeof(VIDEO_PORT_DEVICE_EXTENSION) + HwDeviceExtensionSize。MiniPortDeviceExtension 紧随端口驱动扩展之后,MiniPort 通过 HwDeviceExtension 参数访问它。这种"端口扩展 + MiniPort 扩展"拼接设计避免了 MiniPort 依赖端口驱动的内部结构。
c
/* 由 MiniPort 扩展地址反推端口扩展地址 */
#define VIDEO_PORT_GET_DEVICE_EXTENSION(MiniportExtension) \
CONTAINING_RECORD(MiniportExtension, VIDEO_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension)
3.3 VIDEO_PORT_CHILD_EXTENSION --- 子设备扩展(显示器 PDO)
c
typedef struct _VIDEO_PORT_CHILD_EXTENSION
{
VIDEO_PORT_COMMON_EXTENSION Common;
ULONG ChildId; // 子设备 ID
VIDEO_CHILD_TYPE ChildType; // Monitor / Other
UCHAR ChildDescriptor[256]; // EDID 数据
BOOLEAN EdidValid; // EDID 是否有效
PDRIVER_OBJECT DriverObject;
PDEVICE_OBJECT PhysicalDeviceObject;
LIST_ENTRY ListEntry;
CHAR ChildDeviceExtension[1]; // MiniPort 子设备扩展
} VIDEO_PORT_CHILD_EXTENSION, *PVIDEO_PORT_CHILD_EXTENSION;
3.4 全局状态
c
BOOLEAN VpBaseVideo = FALSE; // BASEVIDEO 启动选项
BOOLEAN VpNoVesa = FALSE; // NOVESA 启动选项
PKPROCESS CsrProcess = NULL; // CSRSS 进程引用(INT10 V86 模式运行上下文)
ULONG VideoPortMaxObjectNumber; // 已用最大设备编号
KSPIN_LOCK HwResetAdaptersLock; // 可复位适配器链表锁
LIST_ENTRY HwResetAdaptersList; // 可复位适配器链表
KMUTEX VgaSyncLock; // VGA 资源同步锁
PVIDEO_PORT_DEVICE_EXTENSION VgaDeviceExtension; // 已注册的 VGA 设备
4. 主要功能模块分析
4.1 DriverEntry 与 VideoPortInitialize --- MiniPort 注册
DriverEntry 直接返回 STATUS_SUCCESS(videoprt.sys 本身的入口,无实际初始化)。真正的初始化发生在 MiniPort 驱动的 DriverEntry 调用导出函数 VideoPortInitialize 时。
c
ULONG NTAPI VideoPortInitialize(
IN PVOID Context1, // DriverObject
IN PVOID Context2, // RegistryPath
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData, // MiniPort 回调表
IN PVOID HwContext)
初始化流程:
#mermaid-svg-w6imIctwqcpOwKwt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w6imIctwqcpOwKwt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w6imIctwqcpOwKwt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w6imIctwqcpOwKwt .error-icon{fill:#552222;}#mermaid-svg-w6imIctwqcpOwKwt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w6imIctwqcpOwKwt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w6imIctwqcpOwKwt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w6imIctwqcpOwKwt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w6imIctwqcpOwKwt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w6imIctwqcpOwKwt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w6imIctwqcpOwKwt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w6imIctwqcpOwKwt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w6imIctwqcpOwKwt .marker.cross{stroke:#333333;}#mermaid-svg-w6imIctwqcpOwKwt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w6imIctwqcpOwKwt p{margin:0;}#mermaid-svg-w6imIctwqcpOwKwt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-w6imIctwqcpOwKwt .cluster-label text{fill:#333;}#mermaid-svg-w6imIctwqcpOwKwt .cluster-label span{color:#333;}#mermaid-svg-w6imIctwqcpOwKwt .cluster-label span p{background-color:transparent;}#mermaid-svg-w6imIctwqcpOwKwt .label text,#mermaid-svg-w6imIctwqcpOwKwt span{fill:#333;color:#333;}#mermaid-svg-w6imIctwqcpOwKwt .node rect,#mermaid-svg-w6imIctwqcpOwKwt .node circle,#mermaid-svg-w6imIctwqcpOwKwt .node ellipse,#mermaid-svg-w6imIctwqcpOwKwt .node polygon,#mermaid-svg-w6imIctwqcpOwKwt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-w6imIctwqcpOwKwt .rough-node .label text,#mermaid-svg-w6imIctwqcpOwKwt .node .label text,#mermaid-svg-w6imIctwqcpOwKwt .image-shape .label,#mermaid-svg-w6imIctwqcpOwKwt .icon-shape .label{text-anchor:middle;}#mermaid-svg-w6imIctwqcpOwKwt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-w6imIctwqcpOwKwt .rough-node .label,#mermaid-svg-w6imIctwqcpOwKwt .node .label,#mermaid-svg-w6imIctwqcpOwKwt .image-shape .label,#mermaid-svg-w6imIctwqcpOwKwt .icon-shape .label{text-align:center;}#mermaid-svg-w6imIctwqcpOwKwt .node.clickable{cursor:pointer;}#mermaid-svg-w6imIctwqcpOwKwt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-w6imIctwqcpOwKwt .arrowheadPath{fill:#333333;}#mermaid-svg-w6imIctwqcpOwKwt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-w6imIctwqcpOwKwt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-w6imIctwqcpOwKwt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w6imIctwqcpOwKwt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-w6imIctwqcpOwKwt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w6imIctwqcpOwKwt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-w6imIctwqcpOwKwt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-w6imIctwqcpOwKwt .cluster text{fill:#333;}#mermaid-svg-w6imIctwqcpOwKwt .cluster span{color:#333;}#mermaid-svg-w6imIctwqcpOwKwt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-w6imIctwqcpOwKwt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-w6imIctwqcpOwKwt rect.text{fill:none;stroke-width:0;}#mermaid-svg-w6imIctwqcpOwKwt .icon-shape,#mermaid-svg-w6imIctwqcpOwKwt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w6imIctwqcpOwKwt .icon-shape p,#mermaid-svg-w6imIctwqcpOwKwt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-w6imIctwqcpOwKwt .icon-shape .label rect,#mermaid-svg-w6imIctwqcpOwKwt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w6imIctwqcpOwKwt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-w6imIctwqcpOwKwt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-w6imIctwqcpOwKwt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
NT4 大小
W2K 大小
XP 大小
其他
是
否
是
否
VideoPortInitialize 开始
首次调用?
初始化互斥体
VideoPortInt10Mutex/VgaSyncLock/HwResetAdaptersLock
IntLoadRegistryParameters
读启动选项 BASEVIDEO/NOVESA
IntInitializeInt10
初始化 x86 模拟器或 V86
校验 HwInitDataSize?
标记 NT4 传统驱动
标记 W2K 驱动
标记 XP+ 驱动
返回 STATUS_UNSUCCESSFUL
设置分发例程
Create/Close/DeviceControl/Shutdown
是 PnP MiniPort?
(有 HwSetPowerState/HwGetVideoChildDescriptor)
HwContext 为空?
传统检测模式
注册 AddDevice
设置 PnP/Power/SystemControl 分发
分配驱动扩展
保存注册表路径
复制初始化数据
IntVideoPortCreateAdapterDeviceObject
创建 \\Device\\VideoN
IntVideoPortFindAdapter
调用 HwFindAdapter 检测
返回状态
返回 STATUS_SUCCESS
(设备由 PnP 驱动 AddDevice)
类型判定逻辑: 通过 HwInitializationData->HwInitDataSize 区分 NT4(SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA)、W2K、XP 时代的 MiniPort,兼容老驱动。
4.2 IntLoadRegistryParameters --- 启动选项解析
c
VOID FASTCALL IntLoadRegistryParameters(VOID)
{
/* 1. 检查 UseNewKey 键 → 使用新注册表路径格式 */
ZwOpenKey(...\GraphicsDrivers\UseNewKey);
if (成功) VideoPortUseNewKey = TRUE;
/* 2. 检查 DisableEmulator 键 → 强制 V86 模式 */
ZwOpenKey(...\GraphicsDrivers\DisableEmulator);
if (成功) VideoPortDisableX86Emulator = TRUE;
/* 3. 读取 SystemStartOptions 检查 BASEVIDEO / NOVESA */
ZwQueryValueKey(...\Control, "SystemStartOptions", ...);
if (wcsstr(Data, L"BASEVIDEO")) VpBaseVideo = TRUE;
if (wcsstr(Data, L"NOVESA")) VpNoVesa = TRUE;
/* 兼容性:BASEVIDEO 隐含 NOVESA */
if (VpBaseVideo) VpNoVesa = TRUE;
/* 4. BASEVIDEO 模式下创建易失键通知 win32k */
if (VpBaseVideo)
ZwCreateKey(...\GraphicsDrivers\BaseVideo, REG_OPTION_VOLATILE);
}
关键点: win32k 的 InitVideo 正是通过检查 \GraphicsDrivers\BaseVideo 键的存在来决定是否使用基础视频模式。
4.3 设备对象创建 --- IntVideoPortCreateAdapterDeviceObject
#mermaid-svg-oewjJeYQBaMvY5bJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oewjJeYQBaMvY5bJ .error-icon{fill:#552222;}#mermaid-svg-oewjJeYQBaMvY5bJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oewjJeYQBaMvY5bJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oewjJeYQBaMvY5bJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oewjJeYQBaMvY5bJ .marker.cross{stroke:#333333;}#mermaid-svg-oewjJeYQBaMvY5bJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oewjJeYQBaMvY5bJ p{margin:0;}#mermaid-svg-oewjJeYQBaMvY5bJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-oewjJeYQBaMvY5bJ .cluster-label text{fill:#333;}#mermaid-svg-oewjJeYQBaMvY5bJ .cluster-label span{color:#333;}#mermaid-svg-oewjJeYQBaMvY5bJ .cluster-label span p{background-color:transparent;}#mermaid-svg-oewjJeYQBaMvY5bJ .label text,#mermaid-svg-oewjJeYQBaMvY5bJ span{fill:#333;color:#333;}#mermaid-svg-oewjJeYQBaMvY5bJ .node rect,#mermaid-svg-oewjJeYQBaMvY5bJ .node circle,#mermaid-svg-oewjJeYQBaMvY5bJ .node ellipse,#mermaid-svg-oewjJeYQBaMvY5bJ .node polygon,#mermaid-svg-oewjJeYQBaMvY5bJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oewjJeYQBaMvY5bJ .rough-node .label text,#mermaid-svg-oewjJeYQBaMvY5bJ .node .label text,#mermaid-svg-oewjJeYQBaMvY5bJ .image-shape .label,#mermaid-svg-oewjJeYQBaMvY5bJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-oewjJeYQBaMvY5bJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oewjJeYQBaMvY5bJ .rough-node .label,#mermaid-svg-oewjJeYQBaMvY5bJ .node .label,#mermaid-svg-oewjJeYQBaMvY5bJ .image-shape .label,#mermaid-svg-oewjJeYQBaMvY5bJ .icon-shape .label{text-align:center;}#mermaid-svg-oewjJeYQBaMvY5bJ .node.clickable{cursor:pointer;}#mermaid-svg-oewjJeYQBaMvY5bJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oewjJeYQBaMvY5bJ .arrowheadPath{fill:#333333;}#mermaid-svg-oewjJeYQBaMvY5bJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oewjJeYQBaMvY5bJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oewjJeYQBaMvY5bJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oewjJeYQBaMvY5bJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oewjJeYQBaMvY5bJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oewjJeYQBaMvY5bJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oewjJeYQBaMvY5bJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oewjJeYQBaMvY5bJ .cluster text{fill:#333;}#mermaid-svg-oewjJeYQBaMvY5bJ .cluster span{color:#333;}#mermaid-svg-oewjJeYQBaMvY5bJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-oewjJeYQBaMvY5bJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oewjJeYQBaMvY5bJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-oewjJeYQBaMvY5bJ .icon-shape,#mermaid-svg-oewjJeYQBaMvY5bJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oewjJeYQBaMvY5bJ .icon-shape p,#mermaid-svg-oewjJeYQBaMvY5bJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oewjJeYQBaMvY5bJ .icon-shape .label rect,#mermaid-svg-oewjJeYQBaMvY5bJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oewjJeYQBaMvY5bJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oewjJeYQBaMvY5bJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oewjJeYQBaMvY5bJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
IntVideoPortCreateAdapterDeviceObject
确定设备编号
DeviceNumber = MaxObjectNumber + 1
IoCreateDevice
名称 \\Device\\VideoN
类型 FILE_DEVICE_VIDEO
扩展 = 端口扩展 + MiniPort扩展
设置 DO_BUFFERED_IO
(所有 IOCTL 用缓冲 I/O)
初始化端口设备扩展
记录 DriverObject/PDO/FDO/AdapterNumber
IsVgaDriver = 驱动名是否为 VgaSave
清零 MiniPortDeviceExtension
IntCreateRegistryPath
创建 \\Services\\xxx\\Device0 路径
有 PDO?
IoGetDeviceProperty
获取总线号/总线类型/槽位号
记录总线号为 0
初始化 DPC 对象和设备锁互斥体
PDO 且 DisplayNumber==0?
IoAttachDeviceToDeviceStack
挂到设备栈
不挂载
IntCreateNewRegistryPath
创建新格式注册表路径
IntSetupDeviceSettingsKey
复制设备设置键
IntVideoPortAddDeviceMapLink
注册表写 \\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO
\\Device\\VideoN → 注册表路径
写 MaxObjectNumber 值
IoCreateSymbolicLink
\\??\\DISPLAYn → \\Device\\VideoN
返回 STATUS_SUCCESS
DEVICEMAP\VIDEO 注册表映射(win32k 正是通过它找到显示设备):
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\VIDEO
\Device\Video0 = \Registry\Machine\System\CurrentControlSet\Services\vga (REG_SZ)
MaxObjectNumber = 0x00000000 (REG_DWORD)
4.4 适配器检测 --- IntVideoPortFindAdapter
PnP 路径与遗留路径:
#mermaid-svg-5X2Jn0TUmCBIRDrq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5X2Jn0TUmCBIRDrq .error-icon{fill:#552222;}#mermaid-svg-5X2Jn0TUmCBIRDrq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5X2Jn0TUmCBIRDrq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .marker.cross{stroke:#333333;}#mermaid-svg-5X2Jn0TUmCBIRDrq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5X2Jn0TUmCBIRDrq p{margin:0;}#mermaid-svg-5X2Jn0TUmCBIRDrq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .cluster-label text{fill:#333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .cluster-label span{color:#333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .cluster-label span p{background-color:transparent;}#mermaid-svg-5X2Jn0TUmCBIRDrq .label text,#mermaid-svg-5X2Jn0TUmCBIRDrq span{fill:#333;color:#333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .node rect,#mermaid-svg-5X2Jn0TUmCBIRDrq .node circle,#mermaid-svg-5X2Jn0TUmCBIRDrq .node ellipse,#mermaid-svg-5X2Jn0TUmCBIRDrq .node polygon,#mermaid-svg-5X2Jn0TUmCBIRDrq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5X2Jn0TUmCBIRDrq .rough-node .label text,#mermaid-svg-5X2Jn0TUmCBIRDrq .node .label text,#mermaid-svg-5X2Jn0TUmCBIRDrq .image-shape .label,#mermaid-svg-5X2Jn0TUmCBIRDrq .icon-shape .label{text-anchor:middle;}#mermaid-svg-5X2Jn0TUmCBIRDrq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5X2Jn0TUmCBIRDrq .rough-node .label,#mermaid-svg-5X2Jn0TUmCBIRDrq .node .label,#mermaid-svg-5X2Jn0TUmCBIRDrq .image-shape .label,#mermaid-svg-5X2Jn0TUmCBIRDrq .icon-shape .label{text-align:center;}#mermaid-svg-5X2Jn0TUmCBIRDrq .node.clickable{cursor:pointer;}#mermaid-svg-5X2Jn0TUmCBIRDrq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .arrowheadPath{fill:#333333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5X2Jn0TUmCBIRDrq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5X2Jn0TUmCBIRDrq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5X2Jn0TUmCBIRDrq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5X2Jn0TUmCBIRDrq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5X2Jn0TUmCBIRDrq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5X2Jn0TUmCBIRDrq .cluster text{fill:#333;}#mermaid-svg-5X2Jn0TUmCBIRDrq .cluster span{color:#333;}#mermaid-svg-5X2Jn0TUmCBIRDrq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5X2Jn0TUmCBIRDrq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5X2Jn0TUmCBIRDrq rect.text{fill:none;stroke-width:0;}#mermaid-svg-5X2Jn0TUmCBIRDrq .icon-shape,#mermaid-svg-5X2Jn0TUmCBIRDrq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5X2Jn0TUmCBIRDrq .icon-shape p,#mermaid-svg-5X2Jn0TUmCBIRDrq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5X2Jn0TUmCBIRDrq .icon-shape .label rect,#mermaid-svg-5X2Jn0TUmCBIRDrq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5X2Jn0TUmCBIRDrq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5X2Jn0TUmCBIRDrq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5X2Jn0TUmCBIRDrq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
ERROR_DEV_NOT_EXIST
其他错误
是
否
NO_ERROR
是
否
是
否
是
否
IntVideoPortFindAdapter
填充 VIDEO_PORT_CONFIG_INFO
InterruptMode/RegistryPath/总线号
SystemMemorySize
有 PDO?
(PnP 设备)
遗留检测
逐总线枚举 IoQueryDeviceDescription
每总线调用 HwFindAdapter
直接调用 HwFindAdapter
HwFindAdapter 返回?
遗留模式还有总线?
失败清理
恢复 VGA 资源
IntVideoPortSetupInterrupt
分配中断
IntVideoPortSetupTimer
分配定时器
HwResetHw 已注册?
加入 HwResetAdaptersList
可复位适配器链表
跳过
是 VGA 驱动?
记录 VgaDeviceExtension
(VgaSyncLock 保护)
继续
遗留设备?
IoReportDetectedDevice
上报遗留 PDO
完成
尝试回收 VGA 资源
返回 STATUS_SUCCESS
VGA 资源动态管理(关键设计):
在探测新适配器前,临时释放 已有 VGA 设备的资源(IntVideoPortReleaseResources),使硬件冲突在检测期间可见;探测结束后回收 (VideoPortVerifyAccessRanges)。若回收失败(被其他驱动占用),则放弃 VGA 回退状态(清空 VgaRanges/VgaDeviceExtension)。这一机制保证了:
- VGA 兼容设备在探测阶段可被其他 MiniPort 抢占
- 无新设备认领时 VGA 模式仍可回退
- framebuf/VGA 显示驱动在启动早期安全使用 VGA 资源
4.5 IRP 分发 --- dispatch.c
VideoPortInitialize 注册的分发例程:
| 主功能号 | 处理函数 | 说明 |
|---|---|---|
| IRP_MJ_CREATE | IntVideoPortDispatchOpen | 打开视频设备(win32k 打开 \Device\Video0) |
| IRP_MJ_CLOSE | IntVideoPortDispatchClose | 关闭设备 |
| IRP_MJ_DEVICE_CONTROL | IntVideoPortDispatchDeviceControl | IOCTL 处理 |
| IRP_MJ_SHUTDOWN | IntVideoPortDispatchDeviceControl | 关机清理 |
| IRP_MJ_PNP | IntVideoPortDispatchPnp | PnP 管理(FDO/PDO) |
| IRP_MJ_POWER | IntVideoPortDispatchPower | 电源管理 |
| IRP_MJ_SYSTEM_CONTROL | IntVideoPortDispatchSystemControl | WMI |
4.5.1 打开设备 --- IntVideoPortDispatchOpen
c
NTSTATUS IntVideoPortDispatchOpen(DeviceObject, Irp)
{
if (!CsrProcess)
{
/* 第一次打开来自 CSRSS,保存其进程引用(INT10 V86 模式需要) */
CsrProcess = PsGetCurrentProcess();
ObReferenceObject(CsrProcess);
Status = IntInitializeInt10(); // 初始化视频地址空间(V86)
}
IntVideoPortInbvInitialize(); // 注册 INBV 显示所有权回调
if (HwInitialize(&MiniPortDeviceExtension)) // 调用 MiniPort 初始化
{
DeviceOpened++; // 打开计数
VideoPortEnumerateChildren(...); // 触发子设备枚举
}
}
4.5.2 IOCTL 处理 --- IntVideoPortDispatchDeviceControl
#mermaid-svg-KzrR7wHWXoSP6k0w{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KzrR7wHWXoSP6k0w .error-icon{fill:#552222;}#mermaid-svg-KzrR7wHWXoSP6k0w .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KzrR7wHWXoSP6k0w .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KzrR7wHWXoSP6k0w .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KzrR7wHWXoSP6k0w .marker.cross{stroke:#333333;}#mermaid-svg-KzrR7wHWXoSP6k0w svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KzrR7wHWXoSP6k0w p{margin:0;}#mermaid-svg-KzrR7wHWXoSP6k0w .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KzrR7wHWXoSP6k0w .cluster-label text{fill:#333;}#mermaid-svg-KzrR7wHWXoSP6k0w .cluster-label span{color:#333;}#mermaid-svg-KzrR7wHWXoSP6k0w .cluster-label span p{background-color:transparent;}#mermaid-svg-KzrR7wHWXoSP6k0w .label text,#mermaid-svg-KzrR7wHWXoSP6k0w span{fill:#333;color:#333;}#mermaid-svg-KzrR7wHWXoSP6k0w .node rect,#mermaid-svg-KzrR7wHWXoSP6k0w .node circle,#mermaid-svg-KzrR7wHWXoSP6k0w .node ellipse,#mermaid-svg-KzrR7wHWXoSP6k0w .node polygon,#mermaid-svg-KzrR7wHWXoSP6k0w .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KzrR7wHWXoSP6k0w .rough-node .label text,#mermaid-svg-KzrR7wHWXoSP6k0w .node .label text,#mermaid-svg-KzrR7wHWXoSP6k0w .image-shape .label,#mermaid-svg-KzrR7wHWXoSP6k0w .icon-shape .label{text-anchor:middle;}#mermaid-svg-KzrR7wHWXoSP6k0w .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KzrR7wHWXoSP6k0w .rough-node .label,#mermaid-svg-KzrR7wHWXoSP6k0w .node .label,#mermaid-svg-KzrR7wHWXoSP6k0w .image-shape .label,#mermaid-svg-KzrR7wHWXoSP6k0w .icon-shape .label{text-align:center;}#mermaid-svg-KzrR7wHWXoSP6k0w .node.clickable{cursor:pointer;}#mermaid-svg-KzrR7wHWXoSP6k0w .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KzrR7wHWXoSP6k0w .arrowheadPath{fill:#333333;}#mermaid-svg-KzrR7wHWXoSP6k0w .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KzrR7wHWXoSP6k0w .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KzrR7wHWXoSP6k0w .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KzrR7wHWXoSP6k0w .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KzrR7wHWXoSP6k0w .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KzrR7wHWXoSP6k0w .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KzrR7wHWXoSP6k0w .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KzrR7wHWXoSP6k0w .cluster text{fill:#333;}#mermaid-svg-KzrR7wHWXoSP6k0w .cluster span{color:#333;}#mermaid-svg-KzrR7wHWXoSP6k0w div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KzrR7wHWXoSP6k0w .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KzrR7wHWXoSP6k0w rect.text{fill:none;stroke-width:0;}#mermaid-svg-KzrR7wHWXoSP6k0w .icon-shape,#mermaid-svg-KzrR7wHWXoSP6k0w .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KzrR7wHWXoSP6k0w .icon-shape p,#mermaid-svg-KzrR7wHWXoSP6k0w .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KzrR7wHWXoSP6k0w .icon-shape .label rect,#mermaid-svg-KzrR7wHWXoSP6k0w .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KzrR7wHWXoSP6k0w .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KzrR7wHWXoSP6k0w .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KzrR7wHWXoSP6k0w :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VDM 类
电源管理类
亮度类
ENUM_MONITOR_PDO
INIT_WIN32K_CALLBACKS
USE_DEVICE_IN_SESSION
PREPARE_FOR_EARECOVERY
其他
IRP_MJ_DEVICE_CONTROL
IOCTL 代码分类
UNIMPLEMENTED
STATUS_NOT_IMPLEMENTED
UNIMPLEMENTED
STATUS_NOT_IMPLEMENTED
UNIMPLEMENTED
VideoPortEnumMonitorPdo
枚举显示器 PDO
VideoPortInitWin32kCallbacks
保存 win32k 回调
VideoPortUseDeviceInSession
会话绑定
复位到 VGA 80x25
(看门狗 EAR 恢复)
VideoPortForwardDeviceControl
转发给 MiniPort HwStartIO
IRP → VRP 转换(VideoPortForwardDeviceControl)------核心桥接:
c
/* 将 IRP 转换为 VIDEO_REQUEST_PACKET 并调用 MiniPort */
VIDEO_REQUEST_PACKET vrp;
vrp.StatusBlock = (PSTATUS_BLOCK)&Irp->IoStatus; // 状态块复用 IRP IoStatus
vrp.IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
vrp.InputBuffer = Irp->AssociatedIrp.SystemBuffer; // METHOD_BUFFERED
vrp.InputBufferLength = ...InputBufferLength;
vrp.OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
vrp.OutputBufferLength = ...OutputBufferLength;
DriverExtension->InitializationData.HwStartIO(&MiniPortDeviceExtension, &vrp);
/* 将 Win32 错误码映射为 NTSTATUS */
switch (Irp->IoStatus.Status)
{
case NO_ERROR: return STATUS_SUCCESS;
case ERROR_NOT_ENOUGH_MEMORY: return STATUS_INSUFFICIENT_RESOURCES;
case ERROR_MORE_DATA: return STATUS_BUFFER_OVERFLOW;
case ERROR_INVALID_FUNCTION: return STATUS_NOT_IMPLEMENTED;
case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL;
case ERROR_DEV_NOT_EXIST: return STATUS_DEVICE_DOES_NOT_EXIST;
case ERROR_IO_PENDING: return STATUS_PENDING;
default: return STATUS_UNSUCCESSFUL;
}
4.5.3 PnP 处理
FDO PnP(IntVideoPortDispatchFdoPnp):
IRP_MN_START_DEVICE:先向下转发,成功后调用IntVideoPortPnPStartDevice保存资源并提取中断信息,再调用IntVideoPortFindAdapterIRP_MN_FILTER_RESOURCE_REQUIREMENTS:调用IntVideoPortFilterResourceRequirements添加传统资源IRP_MN_QUERY_DEVICE_RELATIONS:BusRelations时调用IntVideoPortQueryBusRelations报告子设备(显示器)PDO 列表
4.6 INT 10 BIOS 调用服务 --- int10.c
这是 videoprt 最核心的服务之一,为 MiniPort 提供实模式 BIOS 调用能力。
4.6.1 双实现机制(x86 模拟器 vs V86 模式)
c
/* 两张函数表 */
static const INT10_INTERFACE Int10IFace[2] =
{
/* [0] x86 模拟器:保护模式下用软件模拟实模式指令 */
{ IntInt10AllocateBufferEmu, IntInt10FreeBufferEmu,
IntInt10ReadMemoryEmu, IntInt10WriteMemoryEmu, IntInt10CallBiosEmu },
/* [1] V86 模式:虚拟 8086 模式执行真实 BIOS */
{ IntInt10AllocateBufferV86, IntInt10FreeBufferV86,
IntInt10ReadMemoryV86, IntInt10WriteMemoryV86, IntInt10CallBiosV86 }
};
static const INT10_INTERFACE *Int10Vtbl; // 当前使用的接口表
选择逻辑(IntInitializeInt10):
#mermaid-svg-wrY2DeaoHW3ZRnwA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wrY2DeaoHW3ZRnwA .error-icon{fill:#552222;}#mermaid-svg-wrY2DeaoHW3ZRnwA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wrY2DeaoHW3ZRnwA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .marker.cross{stroke:#333333;}#mermaid-svg-wrY2DeaoHW3ZRnwA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wrY2DeaoHW3ZRnwA p{margin:0;}#mermaid-svg-wrY2DeaoHW3ZRnwA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .cluster-label text{fill:#333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .cluster-label span{color:#333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .cluster-label span p{background-color:transparent;}#mermaid-svg-wrY2DeaoHW3ZRnwA .label text,#mermaid-svg-wrY2DeaoHW3ZRnwA span{fill:#333;color:#333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .node rect,#mermaid-svg-wrY2DeaoHW3ZRnwA .node circle,#mermaid-svg-wrY2DeaoHW3ZRnwA .node ellipse,#mermaid-svg-wrY2DeaoHW3ZRnwA .node polygon,#mermaid-svg-wrY2DeaoHW3ZRnwA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wrY2DeaoHW3ZRnwA .rough-node .label text,#mermaid-svg-wrY2DeaoHW3ZRnwA .node .label text,#mermaid-svg-wrY2DeaoHW3ZRnwA .image-shape .label,#mermaid-svg-wrY2DeaoHW3ZRnwA .icon-shape .label{text-anchor:middle;}#mermaid-svg-wrY2DeaoHW3ZRnwA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wrY2DeaoHW3ZRnwA .rough-node .label,#mermaid-svg-wrY2DeaoHW3ZRnwA .node .label,#mermaid-svg-wrY2DeaoHW3ZRnwA .image-shape .label,#mermaid-svg-wrY2DeaoHW3ZRnwA .icon-shape .label{text-align:center;}#mermaid-svg-wrY2DeaoHW3ZRnwA .node.clickable{cursor:pointer;}#mermaid-svg-wrY2DeaoHW3ZRnwA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .arrowheadPath{fill:#333333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wrY2DeaoHW3ZRnwA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wrY2DeaoHW3ZRnwA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wrY2DeaoHW3ZRnwA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wrY2DeaoHW3ZRnwA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wrY2DeaoHW3ZRnwA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wrY2DeaoHW3ZRnwA .cluster text{fill:#333;}#mermaid-svg-wrY2DeaoHW3ZRnwA .cluster span{color:#333;}#mermaid-svg-wrY2DeaoHW3ZRnwA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wrY2DeaoHW3ZRnwA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wrY2DeaoHW3ZRnwA rect.text{fill:none;stroke-width:0;}#mermaid-svg-wrY2DeaoHW3ZRnwA .icon-shape,#mermaid-svg-wrY2DeaoHW3ZRnwA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wrY2DeaoHW3ZRnwA .icon-shape p,#mermaid-svg-wrY2DeaoHW3ZRnwA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wrY2DeaoHW3ZRnwA .icon-shape .label rect,#mermaid-svg-wrY2DeaoHW3ZRnwA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wrY2DeaoHW3ZRnwA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wrY2DeaoHW3ZRnwA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wrY2DeaoHW3ZRnwA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
否
是
IntInitializeInt10
首次初始化?
IntInitializeVideoAddressSpace
(V86: 映射低 1MB 地址空间)
VideoPortDisableX86Emulator?
IntInitializeX86Emu
MmGetSystemRoutineAddress 加载
x86BiosCall 等 HAL 导出
加载成功?
Int10Vtbl = &Int10IFace0
使用 x86 模拟器
回退 V86 模式
Int10Vtbl = &Int10IFace1
返回 STATUS_SUCCESS
对应串口日志:
(win32ss/drivers/videoprt/videoprt.c:816) Using x86 emulator
(win32ss/drivers/videoprt/int10.c:781) Could not initialize the x86 emulator; falling back to V86 mode
(在测试的 VirtualBox 虚拟机中,x86 模拟器初始化失败,实际回退到 V86 模式。)
4.6.2 V86 模式地址空间初始化
c
static NTSTATUS IntInitializeVideoAddressSpace(VOID)
{
/* 1. 释放 CSRSS 进程预留的 1MB 区域 */
ZwFreeVirtualMemory(NtCurrentProcess(), &BaseAddress(0), 1MB, MEM_RELEASE);
/* 2. 打开 \Device\PhysicalMemory 段 */
ZwOpenSection(&PhysMemHandle, SECTION_ALL_ACCESS, ...);
/* 3. 将 0xA0000-0x100000 (BIOS/显存区) 映射进 CSRSS 地址空间 */
Offset.QuadPart = 0xa0000;
ZwMapViewOfSection(PhysMemHandle, NtCurrentProcess(),
&BaseAddress(0xa0000), 0, 0x60000, &Offset, ...,
PAGE_EXECUTE_READWRITE);
/* 4. 在 0x0-0xA0000 分配可执行低内存(V86 代码与数据区) */
ZwAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress(0x1),
0xa0000 - 0x1000, MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
/* 5. 从内核获取实模式 IVT 和 BDA */
NtVdmControl(VdmInitialize, IVTAndBda);
/* 6. 保护低内存:除 INT10 调用期间外禁止访问 */
ProtectLowV86Mem(); // 0x0-0xA0000 设为 PAGE_NOACCESS
}
为什么要用 CSRSS 进程? V86 模式调用 BIOS 时,需要进程的地址空间能直接映射物理内存 0-1MB 区域。CSRSS 是第一个打开视频设备的用户模式进程,videoprt 借用它的地址空间来构造 V86 环境(KeStackAttachProcess)。
4.6.3 Int10CallBios --- BIOS 调用核心
c
static VP_STATUS IntInt10CallBiosV86(Context, BiosArguments)
{
/* 复制寄存器上下文(Eax..SegEs) */
...
/* 挂到 CSRSS 进程上下文 */
IntAttachToCSRSS(&CallingProcess, &ApcState);
/* 互斥保护(BIOS 不可重入) */
KeWaitForMutexObject(&VideoPortInt10Mutex, ...);
/* 临时开放低内存访问 */
UnprotectLowV86Mem();
/* 在 SEH 保护下调用 V86 监控器执行 INT 10 */
_SEH2_TRY
{
Status = Ke386CallBios(0x10, &BiosContext);
}
_SEH2_EXCEPT(...) { Status = _SEH2_GetExceptionCode(); }
_SEH2_END;
ProtectLowV86Mem();
KeReleaseMutex(&VideoPortInt10Mutex, FALSE);
IntDetachFromCSRSS(CallingProcess, &ApcState);
/* 回写寄存器结果(AX 含返回码 0x004F=成功) */
}
x86 模拟器路径(IntInt10CallBiosEmu)类似,但直接调用 HAL 的 x86BiosCall(0x10, &BiosContext),无需 CSRSS 上下文。
4.6.4 对 MiniPort 暴露的接口
MiniPort 通过 VideoPortQueryServices(HwDeviceExtension, VideoPortServicesInt10, &Interface) 获取:
c
typedef struct _INT10_INTERFACE // 即 VIDEO_PORT_INT10_INTERFACE
{
PINT10_ALLOCATE_BUFFER Int10AllocateBuffer; // 分配低 1MB 实模式缓冲区
PINT10_FREE_BUFFER Int10FreeBuffer;
PINT10_READ_MEMORY Int10ReadMemory; // 读实模式内存
PINT10_WRITE_MEMORY Int10WriteMemory; // 写实模式内存
PINT10_CALL_BIOS Int10CallBios; // 执行 BIOS 中断
} INT10_INTERFACE;
vgapnp.sys 正是使用这套接口完成 VBE 调用(见 ReactOS图形系统分析_1.md)。
4.7 子设备(显示器)枚举 --- IntVideoPortEnumerateChildren
#mermaid-svg-EifCHiO9XPkKBmq3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EifCHiO9XPkKBmq3 .error-icon{fill:#552222;}#mermaid-svg-EifCHiO9XPkKBmq3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EifCHiO9XPkKBmq3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EifCHiO9XPkKBmq3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EifCHiO9XPkKBmq3 .marker.cross{stroke:#333333;}#mermaid-svg-EifCHiO9XPkKBmq3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EifCHiO9XPkKBmq3 p{margin:0;}#mermaid-svg-EifCHiO9XPkKBmq3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EifCHiO9XPkKBmq3 .cluster-label text{fill:#333;}#mermaid-svg-EifCHiO9XPkKBmq3 .cluster-label span{color:#333;}#mermaid-svg-EifCHiO9XPkKBmq3 .cluster-label span p{background-color:transparent;}#mermaid-svg-EifCHiO9XPkKBmq3 .label text,#mermaid-svg-EifCHiO9XPkKBmq3 span{fill:#333;color:#333;}#mermaid-svg-EifCHiO9XPkKBmq3 .node rect,#mermaid-svg-EifCHiO9XPkKBmq3 .node circle,#mermaid-svg-EifCHiO9XPkKBmq3 .node ellipse,#mermaid-svg-EifCHiO9XPkKBmq3 .node polygon,#mermaid-svg-EifCHiO9XPkKBmq3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EifCHiO9XPkKBmq3 .rough-node .label text,#mermaid-svg-EifCHiO9XPkKBmq3 .node .label text,#mermaid-svg-EifCHiO9XPkKBmq3 .image-shape .label,#mermaid-svg-EifCHiO9XPkKBmq3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-EifCHiO9XPkKBmq3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EifCHiO9XPkKBmq3 .rough-node .label,#mermaid-svg-EifCHiO9XPkKBmq3 .node .label,#mermaid-svg-EifCHiO9XPkKBmq3 .image-shape .label,#mermaid-svg-EifCHiO9XPkKBmq3 .icon-shape .label{text-align:center;}#mermaid-svg-EifCHiO9XPkKBmq3 .node.clickable{cursor:pointer;}#mermaid-svg-EifCHiO9XPkKBmq3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EifCHiO9XPkKBmq3 .arrowheadPath{fill:#333333;}#mermaid-svg-EifCHiO9XPkKBmq3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EifCHiO9XPkKBmq3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EifCHiO9XPkKBmq3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EifCHiO9XPkKBmq3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EifCHiO9XPkKBmq3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EifCHiO9XPkKBmq3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EifCHiO9XPkKBmq3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EifCHiO9XPkKBmq3 .cluster text{fill:#333;}#mermaid-svg-EifCHiO9XPkKBmq3 .cluster span{color:#333;}#mermaid-svg-EifCHiO9XPkKBmq3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EifCHiO9XPkKBmq3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EifCHiO9XPkKBmq3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-EifCHiO9XPkKBmq3 .icon-shape,#mermaid-svg-EifCHiO9XPkKBmq3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EifCHiO9XPkKBmq3 .icon-shape p,#mermaid-svg-EifCHiO9XPkKBmq3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EifCHiO9XPkKBmq3 .icon-shape .label rect,#mermaid-svg-EifCHiO9XPkKBmq3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EifCHiO9XPkKBmq3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EifCHiO9XPkKBmq3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EifCHiO9XPkKBmq3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
是
否
VIDEO_ENUM_MORE_DEVICES
VIDEO_ENUM_INVALID_DEVICE
VIDEO_ENUM_NO_MORE_DEVICES
是
否
是
否
是
否
IntVideoPortEnumerateChildren
HwGetVideoChildDescriptor 已注册?
返回,无法枚举
ChildDeviceList 非空?
(重复枚举/热插拔)
遍历现有子设备
重新探测每个 ChildId
不再存在的移除出链表
首次枚举
ChildId 从 1 开始
为新子设备创建 PDO
IoCreateDevice FILE_DEVICE_CONTROLLER
调用 HwGetVideoChildDescriptor
传入 ChildId 获取类型和描述
类型为 Monitor?
删除 PDO,继续
删除 PDO,结束
EDID 签名合法?
(00 FF FF FF FF FF FF 00)
记录 EdidValid=FALSE
EdidValid=TRUE
保存 10 字节 Monitor ID
与上一显示器 ID 相同?
认为是重复设备,停止枚举
打印 EDID 数据
加入 ChildDeviceList
返回 STATUS_SUCCESS
EDID 校验: 检查 EDID 头部 8 字节签名 00 FF FF FF FF FF FF 00,并用 EDID 偏移 8 处的 10 字节厂商/产品 ID 区分不同显示器(处理多个显示器时防止重复枚举)。
4.8 INBV 显示所有权管理
显示所有权机制(NT 5.x):启动时 INBV 拥有显示;win32k 打开 DISPLAY 设备后 videoprt 通过 InbvNotifyDisplayOwnershipLost 收回所有权;崩溃(bugcheck)时 INBV 重新接管。
c
/* 复位所有可复位适配器(HwResetHw 回调链) */
IntVideoPortResetDisplayParametersEx(Columns, Rows)
→ 遍历 HwResetAdaptersList
→ 对 DeviceOpened>=1 且注册了 HwResetHw 的设备调用 HwResetHw
/* INBV 监控线程:轮询显示所有权状态 */
InbvMonitorThread()
→ 等待 InbvMonitoring 标志
→ 轮询 InbvCheckDisplayOwnership()
→ 所有权释放后重新注册复位回调
→ 通过 Win32kCallout 通知 win32k 重置显示
IOCTL_VIDEO_PREPARE_FOR_EARECOVERY 即调用复位逻辑:win32k 看门狗(watchdog.sys)检测到显示驱动卡死(将触发 bugcheck 0xEA)前,把显示复位到 VGA 80x25 文本模式。
5. 与 vgapnp.sys 的协作(INT 10 服务视角)
VBE BIOS V86 监控器/CSRSS 地址空间 videoprt.sys (端口驱动) vgapnp.sys (MiniPort) VBE BIOS V86 监控器/CSRSS 地址空间 videoprt.sys (端口驱动) vgapnp.sys (MiniPort) #mermaid-svg-sTN3qwL8lSOhgOg9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sTN3qwL8lSOhgOg9 .error-icon{fill:#552222;}#mermaid-svg-sTN3qwL8lSOhgOg9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sTN3qwL8lSOhgOg9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sTN3qwL8lSOhgOg9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sTN3qwL8lSOhgOg9 .marker.cross{stroke:#333333;}#mermaid-svg-sTN3qwL8lSOhgOg9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sTN3qwL8lSOhgOg9 p{margin:0;}#mermaid-svg-sTN3qwL8lSOhgOg9 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sTN3qwL8lSOhgOg9 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-sTN3qwL8lSOhgOg9 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-sTN3qwL8lSOhgOg9 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-sTN3qwL8lSOhgOg9 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-sTN3qwL8lSOhgOg9 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-sTN3qwL8lSOhgOg9 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-sTN3qwL8lSOhgOg9 .sequenceNumber{fill:white;}#mermaid-svg-sTN3qwL8lSOhgOg9 #sequencenumber{fill:#333;}#mermaid-svg-sTN3qwL8lSOhgOg9 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-sTN3qwL8lSOhgOg9 .messageText{fill:#333;stroke:none;}#mermaid-svg-sTN3qwL8lSOhgOg9 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sTN3qwL8lSOhgOg9 .labelText,#mermaid-svg-sTN3qwL8lSOhgOg9 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-sTN3qwL8lSOhgOg9 .loopText,#mermaid-svg-sTN3qwL8lSOhgOg9 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-sTN3qwL8lSOhgOg9 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-sTN3qwL8lSOhgOg9 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-sTN3qwL8lSOhgOg9 .noteText,#mermaid-svg-sTN3qwL8lSOhgOg9 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-sTN3qwL8lSOhgOg9 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sTN3qwL8lSOhgOg9 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sTN3qwL8lSOhgOg9 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sTN3qwL8lSOhgOg9 .actorPopupMenu{position:absolute;}#mermaid-svg-sTN3qwL8lSOhgOg9 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-sTN3qwL8lSOhgOg9 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sTN3qwL8lSOhgOg9 .actor-man circle,#mermaid-svg-sTN3qwL8lSOhgOg9 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-sTN3qwL8lSOhgOg9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DriverEntry → VideoPortInitialize(注册 Hw 回调表)返回(驱动扩展已建)VideoPortQueryServices(VideoPortServicesInt10)返回 INT10 接口表Int10AllocateBuffer(Seg,Off)在 CSRSS 低地址空间分配 0x20000Seg:Off段:偏移Int10WriteMemory(Seg,Off,"VBE2")Int10CallBios(AX=0x4F00, ES:DI=Seg:Off)挂到 CSRSS + 开放低内存Ke386CallBios(INT 10)将 VBE_INFO 写入 ES:DI 缓冲区AX=0x004F返回寄存器Int10ReadMemory(Seg,Off,&VbeInfo)VBE_INFO 数据
6. 启动流程(完整链路)
framebuf.dll win32k.sys vgapnp.sys videoprt.sys PnP 管理器 framebuf.dll win32k.sys vgapnp.sys videoprt.sys PnP 管理器 #mermaid-svg-wMRHqcAa9MGOss9u{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wMRHqcAa9MGOss9u .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wMRHqcAa9MGOss9u .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wMRHqcAa9MGOss9u .error-icon{fill:#552222;}#mermaid-svg-wMRHqcAa9MGOss9u .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wMRHqcAa9MGOss9u .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wMRHqcAa9MGOss9u .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wMRHqcAa9MGOss9u .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wMRHqcAa9MGOss9u .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wMRHqcAa9MGOss9u .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wMRHqcAa9MGOss9u .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wMRHqcAa9MGOss9u .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wMRHqcAa9MGOss9u .marker.cross{stroke:#333333;}#mermaid-svg-wMRHqcAa9MGOss9u svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wMRHqcAa9MGOss9u p{margin:0;}#mermaid-svg-wMRHqcAa9MGOss9u .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-wMRHqcAa9MGOss9u text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-wMRHqcAa9MGOss9u .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-wMRHqcAa9MGOss9u .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-wMRHqcAa9MGOss9u .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-wMRHqcAa9MGOss9u .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-wMRHqcAa9MGOss9u #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-wMRHqcAa9MGOss9u .sequenceNumber{fill:white;}#mermaid-svg-wMRHqcAa9MGOss9u #sequencenumber{fill:#333;}#mermaid-svg-wMRHqcAa9MGOss9u #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-wMRHqcAa9MGOss9u .messageText{fill:#333;stroke:none;}#mermaid-svg-wMRHqcAa9MGOss9u .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-wMRHqcAa9MGOss9u .labelText,#mermaid-svg-wMRHqcAa9MGOss9u .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-wMRHqcAa9MGOss9u .loopText,#mermaid-svg-wMRHqcAa9MGOss9u .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-wMRHqcAa9MGOss9u .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-wMRHqcAa9MGOss9u .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-wMRHqcAa9MGOss9u .noteText,#mermaid-svg-wMRHqcAa9MGOss9u .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-wMRHqcAa9MGOss9u .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-wMRHqcAa9MGOss9u .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-wMRHqcAa9MGOss9u .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-wMRHqcAa9MGOss9u .actorPopupMenu{position:absolute;}#mermaid-svg-wMRHqcAa9MGOss9u .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-wMRHqcAa9MGOss9u .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-wMRHqcAa9MGOss9u .actor-man circle,#mermaid-svg-wMRHqcAa9MGOss9u line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-wMRHqcAa9MGOss9u :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 服务 vga (ImagePath=vgapnp.sys) 依赖 videoprt 加载 videoprt.sys加载 vgapnp.sys → DriverEntryVideoPortInitialize (注册回调 + 检测模式判断)IntLoadRegistryParametersIntInitializeInt10 (回退 V86)AddDevice → 创建 \Device\Video0 + DISPLAY1 符号链接IRP_MN_START_DEVICE → IntVideoPortFindAdapterHwFindAdapter (报 VDM 内存范围)IRP_MN_QUERY_DEVICE_RELATIONS (BusRelations)HwGetVideoChildDescriptor (枚举显示器/EDID)InitVideo: 读 DEVICEMAP\VIDEO + InstalledDisplayDrivers打开 \Device\Video0 (IRP_MJ_CREATE)HwInitialize (VBEInitialize: 枚举模式)收回 INBV 显示所有权加载 framebuf.dll → DrvEnablePDEVIOCTL_VIDEO_QUERY_AVAIL_MODESHwStartIO → VBEQueryAvailModesIOCTL_VIDEO_SET_CURRENT_MODEHwStartIO → VBESetCurrentMode (0x4F02)IOCTL_VIDEO_MAP_VIDEO_MEMORYHwStartIO → VBEMapVideoMemoryVideoPortMapMemory (映射帧缓冲)帧缓冲虚拟地址
7. 构建与导出
cmake
# CMakeLists.txt 要点
spec2def(videoprt.sys videoprt.spec ADD_IMPORTLIB) # 从 spec 生成 .def
add_library(videoprt MODULE ...) # 内核模块
set_module_type(videoprt kernelmodedriver) # 内核驱动类型
target_link_libraries(videoprt ${PSEH_LIB}) # SEH 支持
add_importlibs(videoprt ntoskrnl hal) # 导入 ntoskrnl + HAL
add_cd_file(TARGET videoprt DESTINATION reactos/system32/drivers) # 安装位置
导出函数分类(videoprt.spec,约 150 个):
| 类别 | 示例 |
|---|---|
| 初始化 | VideoPortInitialize |
| 内存映射 | VideoPortMapMemory、VideoPortUnmapMemory、VideoPortMapBankedMemory |
| 池分配 | VideoPortAllocatePool、VideoPortFreePool、VideoPortAllocateBuffer |
| 端口/寄存器 | VideoPortReadPortUchar ~ VideoPortWriteRegisterUlong(大量) |
| 内存操作 | VideoPortZeroMemory、VideoPortMoveMemory、VideoPortCompareMemory |
| 同步 | VideoPortAcquireSpinLock、VideoPortSynchronizeExecution、VideoPortAcquireDeviceLock |
| 中断 | VideoPortEnableInterrupt、VideoPortDisableInterrupt |
| 定时器 | VideoPortStartTimer、VideoPortStopTimer、VideoPortStallExecution |
| DMA | VideoPortStartDma、VideoPortCompleteDma、VideoPortGetDmaAdapter |
| 事件 | VideoPortCreateEvent、VideoPortSetEvent、VideoPortWaitForSingleObject |
| 注册表 | VideoPortGetRegistryParameters、VideoPortSetRegistryParameters、VideoPortFlushRegistry |
| BIOS | VideoPortInt10、VideoPortQueryServices |
| 子设备 | VideoPortEnumerateChildren、VideoPortGetAssociatedDeviceExtension |
| 诊断 | VideoPortLogError、VideoPortDebugPrint |
| 系统 | VideoPortGetCurrentIrql、VideoPortQueryPerformanceCounter、VideoPortGetVersion |
依赖转发: 大量函数直接转发到 ntoskrnl/hal,如 VideoPortMoveMemory → RtlMoveMemory、VideoPortReadPortUchar → READ_PORT_UCHAR、VideoPortStallExecution → KeStallExecutionProcessor。
8. 设计特点总结
- MiniPort/Port 分层:MiniPort 零硬件直接操作,所有硬件访问通过 VideoPort* 服务委托端口驱动------这是 NT 视频架构的核心设计,使第三方 MiniPort 二进制兼容。
- 设备扩展拼接 :
VIDEO_PORT_DEVICE_EXTENSION + MiniPortDeviceExtension连续布局,MiniPort 只需知道自己的扩展大小。 - INT10 双路径 :x86 模拟器(保护模式软件模拟)与 V86 模式(Ke386CallBios)动态选择,支持注册表
DisableEmulator强制回退。 - CSRSS 地址空间借用 :V86 模式需要物理内存映射进用户地址空间,借用在 CSRSS 进程中实现,并通过
ProtectLowV86Mem保护低内存防止恶意访问。 - IRP→VRP 转换 :统一把 IRP 翻译为
VIDEO_REQUEST_PACKET调用 HwStartIO,并完成 Win32 错误码 ↔ NTSTATUS 映射。 - VGA 资源动态仲裁:探测阶段临时释放 VGA 资源、失败后回收,保证多适配器共存与 VGA 回退。
- 显示所有权管理:INBV(启动阶段)→ videoprt(图形阶段)→ INBV(bugcheck)的显示所有权转换,支持 EAR 恢复。
- EDID 校验:子设备枚举时验证 EDID 签名并用 Monitor ID 去重,避免多显示器重复枚举。
- 兼容性:通过 HwInitDataSize 兼容 NT4/W2K/XP 三代 MiniPort;注册表路径同时维护新旧两种格式(UseNewKey)。
9. 源码索引
| 文件 | 关键内容 |
|---|---|
| videoprt.c(file:///d:/reactos/win32ss/drivers/videoprt/videoprt.c) | VideoPortInitialize、IntVideoPortFindAdapter、IntVideoPortCreateAdapterDeviceObject、子设备枚举、IntLoadRegistryParameters |
| dispatch.c(file:///d:/reactos/win32ss/drivers/videoprt/dispatch.c) | IRP 分发全套、VideoPortForwardDeviceControl、INBV 显示所有权 |
| int10.c(file:///d:/reactos/win32ss/drivers/videoprt/int10.c) | IntInitializeInt10、V86 地址空间、Int10CallBios 双实现 |
| resource.c(file:///d:/reactos/win32ss/drivers/videoprt/resource.c) | VideoPortMapMemory/GetAccessRanges/VerifyAccessRanges/AllocatePool |
| registry.c(file:///d:/reactos/win32ss/drivers/videoprt/registry.c) | IntCreateNewRegistryPath、IntSetupDeviceSettingsKey |
| services.c(file:///d:/reactos/win32ss/drivers/videoprt/services.c) | VideoPortQueryServices |
| videoprt.spec(file:///d:/reactos/win32ss/drivers/videoprt/videoprt.spec) | 全部导出定义 |
| CMakeLists.txt(file:///d:/reactos/win32ss/drivers/videoprt/CMakeLists.txt) | 构建配置 |
关联模块:
- MiniPort 驱动:miniport/vbe/(file:///d:/reactos/win32ss/drivers/miniport/vbe/vbemp.c)(vgapnp.sys,通过 VideoPort* 服务工作)
- 显示驱动 DDI:displays/framebuf/(file:///d:/reactos/win32ss/drivers/displays/framebuf/enable.c)(framebuf.dll,通过 IOCTL 访问设备)
- win32k 驱动加载:ntuser/display.c(file:///d:/reactos/win32ss/user/ntuser/display.c)(读取 DEVICEMAP\VIDEO 和 InstalledDisplayDrivers)
- 看门狗:drivers/watchdog/(file:///d:/reactos/win32ss/drivers/watchdog/watchdog.c)(EAR 恢复触发复位)
本文档基于 ReactOS 源代码
win32ss/drivers/videoprt/分析(2026 年 8 月)