ReactOS 图形系统分析(2):视频端口驱动 videoprt.sys

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 注册的所有回调:

HwFindAdapterHwInitializeHwStartIOHwResetHwHwGetPowerStateHwSetPowerStateHwGetVideoChildDescriptor 等。

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) + HwDeviceExtensionSizeMiniPortDeviceExtension 紧随端口驱动扩展之后,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)。这一机制保证了:

  1. VGA 兼容设备在探测阶段可被其他 MiniPort 抢占
  2. 无新设备认领时 VGA 模式仍可回退
  3. 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 保存资源并提取中断信息,再调用 IntVideoPortFindAdapter
  • IRP_MN_FILTER_RESOURCE_REQUIREMENTS:调用 IntVideoPortFilterResourceRequirements 添加传统资源
  • IRP_MN_QUERY_DEVICE_RELATIONSBusRelations 时调用 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 → RtlMoveMemoryVideoPortReadPortUchar → READ_PORT_UCHARVideoPortStallExecution → KeStallExecutionProcessor


8. 设计特点总结

  1. MiniPort/Port 分层:MiniPort 零硬件直接操作,所有硬件访问通过 VideoPort* 服务委托端口驱动------这是 NT 视频架构的核心设计,使第三方 MiniPort 二进制兼容。
  2. 设备扩展拼接VIDEO_PORT_DEVICE_EXTENSION + MiniPortDeviceExtension 连续布局,MiniPort 只需知道自己的扩展大小。
  3. INT10 双路径 :x86 模拟器(保护模式软件模拟)与 V86 模式(Ke386CallBios)动态选择,支持注册表 DisableEmulator 强制回退。
  4. CSRSS 地址空间借用 :V86 模式需要物理内存映射进用户地址空间,借用在 CSRSS 进程中实现,并通过 ProtectLowV86Mem 保护低内存防止恶意访问。
  5. IRP→VRP 转换 :统一把 IRP 翻译为 VIDEO_REQUEST_PACKET 调用 HwStartIO,并完成 Win32 错误码 ↔ NTSTATUS 映射。
  6. VGA 资源动态仲裁:探测阶段临时释放 VGA 资源、失败后回收,保证多适配器共存与 VGA 回退。
  7. 显示所有权管理:INBV(启动阶段)→ videoprt(图形阶段)→ INBV(bugcheck)的显示所有权转换,支持 EAR 恢复。
  8. EDID 校验:子设备枚举时验证 EDID 签名并用 Monitor ID 去重,避免多显示器重复枚举。
  9. 兼容性:通过 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 月)

相关推荐
AI视觉网奇2 小时前
动作识别 视频理解大模型
开发语言·python·音视频
DogDaoDao2 小时前
NNVC-17.1 深度解析:神经网络视频编码的最新进展与性能全景
神经网络·音视频·视频编解码·h266·vvc·vtm·nnvc
科技新资讯2 小时前
视频出海精细化升级:帧级对口型技术与商用工具落地能力分析
人工智能·音视频
诸葛大钢铁2 小时前
视频转音频怎么转换?在线工具、VLC、FFmpeg 三种方法详解
ffmpeg·音视频·mp4转mp3·视频转音频·视频转mp3·视频提取音频
xingyuzhisuan3 小时前
团队实践:引入 Vera 1.1 之后,视频内容团队工作流重构
人工智能·重构·音视频
美狐美颜SDK开放平台4 小时前
第三方美颜SDK接入教程:直播APP实现实时美颜、滤镜与美型效果的方法
人工智能·深度学习·音视频·sdk·美颜sdk·视频美颜sdk·直播app开发
AI服务老曹16 小时前
边云协同视频分析性能优化指南:多站点部署下的资源瓶颈突破与调优实战
性能优化·音视频
wxson728218 小时前
【Android视频监控系统技术总结】
android·音视频
程序员老陆19 小时前
FFmpeg6操作 RTMP参数详解
ffmpeg·音视频·rtmp