ReactOS 硬件资源仲裁器 (Arbiter) 完整实现计划
概述
本计划目标是以增量方式完整实现 sdk/lib/drivers/arbiter/arbiter.c 的全部 21 个函数,并更新所有调用方以正确使用仲裁器功能。当前该库仅有 ArbInitializeArbiterInstance 完成实现,其余 20 个函数均为 UNIMPLEMENTED 存根。
当前状态分析
已实现的基础设施
- RTL Range List (
sdk/lib/rtl/rangelist.c): 完整可用,提供RtlAddRange、RtlFindRange、RtlDeleteRange、RtlInvertRangeList、RtlIsRangeAvailable、RtlMergeRangeLists等 - 数据结构 (
sdk/lib/drivers/arbiter/arbiter.h):ARBITER_INSTANCE、ARBITER_ALLOCATION_STATE、ARBITER_ORDERING_LIST、ARBITER_ALTERNATIVE已正确定义 - 初始化 (
ArbInitializeArbiterInstance): 已完成,含内存分配、错误回滚、默认回调设置
调用方现状
| 调用方 | 文件 | 当前状态 |
|---|---|---|
| Root IRQ Arbiter | ntoskrnl/io/pnpmgr/arb/arbirq.c |
回调函数全部 UNIMPLEMENTED |
| Root Memory Arbiter | ntoskrnl/io/pnpmgr/arb/arbmem.c |
回调函数全部 UNIMPLEMENTED |
| Root Bus Number Arbiter | ntoskrnl/io/pnpmgr/arb/arbbus.c |
回调函数全部 UNIMPLEMENTED |
| PCI I/O Arbiter | drivers/bus/pcix/arb/ar_memio.c |
ario_Initializer/armem_Initializer 为 UNIMPLEMENTED |
| PCI Bus Number Arbiter | drivers/bus/pcix/arb/ar_busno.c |
arbusno_Initializer 为 UNIMPLEMENTED |
| PCI Common Arbiter | drivers/bus/pcix/arb/arb_comn.c |
PciInitializeArbiterRanges 为 UNIMPLEMENTED |
| I/O Resource Manager | ntoskrnl/io/iomgr/iorsrce.c |
IoReportResourceUsage / IopLegacyResourceAllocation 为 halfplemented |
| PnP Resource Manager | ntoskrnl/io/pnpmgr/pnpres.c |
IopFixupResourceListWithRequirements 存在但不使用仲裁器 |
关键依赖关系
IoAssignResources
→ IopLegacyResourceAllocation (iorsrce.c, halfplemented)
→ IopFixupResourceListWithRequirements (pnpres.c, 简单匹配)
→ [未来] 应调用 ArbTestAllocation / ArbCommitAllocation
IopArbIrqInitialize / IopArbMemInitialize / IopArbBusNumberInitialize
→ ArbInitializeArbiterInstance (arbiter.c, 已实现)
→ 提供 UnpackRequirement / PackResource / UnpackResource / ScoreRequirement 回调
PnP 设备资源分配流程 (pnpres.c):
HalAdjustResourceList → IopFixupResourceListWithRequirements
→ IopDetectResourceConflict → [未来] 应使用仲裁器检测冲突
Windows ARBITER_ACTION 参考
ArbiterActionTestAllocation - 测试分配是否可行
ArbiterActionRetestAllocation - 重新测试分配
ArbiterActionCommitAllocation - 提交/生效分配
ArbiterActionRollbackAllocation - 回滚分配
ArbiterActionQueryAllocatedResources - 查询已分配资源
ArbiterActionWriteReservedResources - 写入保留资源
ArbiterActionQueryConflict - 查询冲突
ArbiterActionQueryArbitrate - 查询仲裁结果
ArbiterActionAddReserved - 添加保留资源
ArbiterActionBootAllocation - 启动时分配
实施计划(共 7 个阶段)
阶段 1: 排序列表管理 (Ordering List Management)
目标: 实现排序列表的创建、释放、添加、裁剪和构建功能。
涉及文件
1.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbInitializeOrderingList |
244 | UNIMPLEMENTED | 实现 |
ArbFreeOrderingList |
256 | UNIMPLEMENTED | 实现 |
ArbAddOrdering |
216 | UNIMPLEMENTED | 实现 |
ArbPruneOrdering |
230 | UNIMPLEMENTED | 实现 |
ArbBuildAssignmentOrdering |
267 | UNIMPLEMENTED | 实现 |
实现细节:
-
ArbInitializeOrderingList: 初始化ARBITER_ORDERING_LIST结构的Count和Maximum字段,为Orderings数组分配初始内存(如 16 个条目)。如果Maximum已非零表示调用方已预分配,则直接重置Count = 0。 -
ArbFreeOrderingList: 如果Orderings非 NULL 且Maximum > 0(表示由库分配),调用ExFreePoolWithTag释放。重置所有字段为零。 -
ArbAddOrdering: 检查列表是否已满(Count >= Maximum),如果是则用ExAllocatePoolWithTag扩容(翻倍策略)。添加新排序条目(Start、End),递增Count。 -
ArbPruneOrdering: 遍历排序列表,删除与[MinimumAddress, MaximumAddress]无交集的条目。对于部分重叠的条目,裁剪起始或结束地址。 -
ArbBuildAssignmentOrdering: 核心函数。先ArbFreeOrderingList清空,然后从总线设备对象获取可用资源范围(CM 资源描述符),通过TranslateOrderingFunction回调转换为 IO 资源描述符,再用ArbAddOrdering添加到排序列表。如果ReservedOrderName非空,也构建保留列表。
测试/验证: 构建 bootcd 验证不再出现 UNIMPLEMENTED 警告。
阶段 2: 核心分配算法 (Allocation Algorithm)
目标: 实现基于回溯 (backtracking) 的资源分配算法核心。
涉及文件
2.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbPreprocessEntry |
89 | 空实现 | 完整实现 |
ArbAllocateEntry |
101 | UNIMPLEMENTED | 完整实现 |
ArbGetNextAllocationRange |
114 | UNIMPLEMENTED | 完整实现 |
ArbFindSuitableRange |
127 | UNIMPLEMENTED | 完整实现 |
ArbAddAllocation |
140 | UNIMPLEMENTED | 完整实现 |
ArbBacktrackAllocation |
152 | UNIMPLEMENTED | 完整实现 |
实现细节:
2.1.1 ArbPreprocessEntry
- 从
ARBITER_LIST_ENTRY中提取资源需求 - 使用
UnpackRequirement回调解析IO_RESOURCE_DESCRIPTOR - 初始化
ARBITER_ALLOCATION_STATE的字段:Start、End、CurrentMinimum、CurrentMaximum - 构建
Alternatives数组(替代资源方案),计算AlternativeCount - 按优先级排序替代方案
2.1.2 ArbGetNextAllocationRange
- 实现为状态机迭代器
- 从
CurrentAlternative开始,依次遍历所有替代方案 - 对每个替代方案,结合
PossibleAllocation范围列表,计算实际可分配的地址范围 - 使用
RtlFindRange在可用范围内查找未占用的区间 - 返回
TRUE找到下一个范围,FALSE已无更多范围
2.1.3 ArbFindSuitableRange
- 在
ArbGetNextAllocationRange返回的范围内,由高到低尝试 - 使用
RtlIsRangeAvailable检查是否与已分配资源冲突 - 考虑对齐约束 (
Alignment) 和长度 (Length),计算合适的起始地址 - 使用
ROUND_DOWN对齐逻辑(参考RtlFindRange)
2.1.4 ArbAddAllocation
- 使用已确定的地址范围,调用
RtlAddRange添加到Allocation列表 - 标记分配的属性 (
Attributes) 和所有者 - 在分配栈 (
AllocationStack) 上记录当前分配状态,用于回溯
2.1.5 ArbBacktrackAllocation
- 从分配栈弹出上一次分配的记录
- 调用
RtlDeleteRange从Allocation列表中删除 - 恢复
ARBITER_ALLOCATION_STATE到回溯前的状态
2.1.6 ArbAllocateEntry
- 这是分配算法的入口,实现完整的分配循环:
- 调用
ArbPreprocessEntry初始化状态 - 循环:
a. 调用ArbGetNextAllocationRange获取下一个可分配范围
b. 调用ArbFindSuitableRange在范围内找合适区间
c. 找到则ArbAddAllocation,返回成功
d. 未找到则ArbBacktrackAllocation,尝试下一个替代方案 - 所有方案尝试失败,返回
STATUS_NO_MORE_ENTRIES
- 调用
算法伪代码:
ArbAllocateEntry(Arbiter, ArbState):
Status = ArbPreprocessEntry(Arbiter, ArbState)
if FAILED(Status): return Status
while TRUE:
HasRange = ArbGetNextAllocationRange(Arbiter, ArbState)
if !HasRange:
// No more ranges for current alternative
CouldBacktrack = ArbBacktrackAllocation(Arbiter, ArbState)
if !CouldBacktrack:
return STATUS_NO_MORE_ENTRIES
continue
Found = ArbFindSuitableRange(Arbiter, ArbState)
if Found:
ArbAddAllocation(Arbiter, ArbState)
return STATUS_SUCCESS
// Continue to next range
阶段 3: 事务管理 (Transaction Management)
目标: 实现资源分配的完整事务生命周期。
涉及文件
3.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbTestAllocation |
26 | UNIMPLEMENTED | 完整实现 |
ArbRetestAllocation |
39 | UNIMPLEMENTED | 完整实现 |
ArbCommitAllocation |
52 | UNIMPLEMENTED | 完整实现 |
ArbRollbackAllocation |
64 | UNIMPLEMENTED | 完整实现 |
实现细节:
3.1.1 ArbTestAllocation
- 加锁:
KeWaitForSingleObject(Arbiter->MutexEvent, ...) - 复制
Allocation到临时范围列表(模拟分配的基础状态) - 遍历
ArbitrationList中的每个ARBITER_LIST_ENTRY:- 对每个条目调用
ArbAllocateEntry尝试分配 - 如果分配失败,回滚所有已分配条目,返回
STATUS_CONFLICTING_ADDRESSES
- 对每个条目调用
- 所有条目分配成功,记录但不提交
- 解锁
- 返回
STATUS_SUCCESS
3.1.2 ArbRetestAllocation
- 与
ArbTestAllocation类似,但不清除之前的测试结果 - 在已有测试分配的基础上,追加测试新的条目
- 用于分步验证资源分配
3.1.3 ArbCommitAllocation
- 加锁
- 将
ArbitrationList中的分配结果写入仲裁器的正式Allocation列表 - 从
PossibleAllocation中移除已分配的范围(使用RtlDeleteRange) - 设置
TransactionInProgress = TRUE - 同步分配结果到硬件(调用
PackResource回调更新设备资源配置) - 解锁
- 返回
STATUS_SUCCESS
3.1.4 ArbRollbackAllocation
- 加锁
- 清理临时分配状态
- 从
Allocation中移除测试分配添加的条目 - 使用分配栈逐层回溯
- 设置
TransactionInProgress = FALSE - 解锁
阶段 4: 启动分配与冲突处理 (Boot & Conflict)
目标: 实现系统启动时的资源分配和冲突检测/处理功能。
涉及文件
4.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbBootAllocation |
177 | UNIMPLEMENTED | 完整实现 |
ArbQueryConflict |
191 | UNIMPLEMENTED | 完整实现 |
ArbOverrideConflict |
165 | UNIMPLEMENTED | 完整实现 |
ArbAddReserved |
77 | UNIMPLEMENTED | 完整实现 |
ArbStartArbiter |
204 | UNIMPLEMENTED | 完整实现 |
实现细节:
4.1.1 ArbBootAllocation
- 接收引导时 BIOS/固件已分配的资源列表
- 遍历
ArbitrationList,对每个条目:- 检查是否已存在于引导资源配置中
- 通过
ScoreRequirement回调评分 - 调用
ArbAllocateEntry尝试分配 - 如果失败,记录冲突但继续
- 将引导分配标记为
ARBITER_FLAG_BOOT_CONFIG
4.1.2 ArbQueryConflict
- 给定
ConflictingResource(一个 IO 资源描述符) - 在
Allocation列表中搜索重叠范围 - 使用
RtlIsRangeAvailable快速判断 - 返回冲突设备列表(
ARBITER_CONFLICT_INFO数组)
4.1.3 ArbOverrideConflict
- 强制分配指定的资源范围
- 使用
RtlAddRange添加到Allocation列表(即使有冲突) - 记录覆盖标记
4.1.4 ArbAddReserved
- 在
ReservedList中添加保留资源 - 这些资源不会通过正常分配流程分配给其他设备
4.1.5 ArbStartArbiter
- 验证仲裁器状态完整性
- 检查
Allocation和PossibleAllocation列表是否已初始化 - 如果尚未有启动分配,调用
ArbBootAllocation
阶段 5: 更新 PnP 根仲裁器回调
目标: 为三个根仲裁器实现具体类型的 Unpack/Pack/Score 回调。
涉及文件
5.1 `ntoskrnl/io/pnpmgr/arb/arbirq.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/arb/arbirq.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopArbIrqUnpackRequirements |
UNIMPLEMENTED | 实现解析 IRQ 需求 |
IopArbIrqPackResource |
UNIMPLEMENTED | 实现打包 IRQ 资源 |
IopArbIrqUnpackResource |
UNIMPLEMENTED | 实现解包 IRQ 资源 |
IopArbIrqScoreRequirement |
UNIMPLEMENTED | 实现 IRQ 评分 |
实现细节:
IopArbIrqUnpackRequirements: 解析IO_RESOURCE_DESCRIPTOR中的u.Interrupt联合体,提取MinimumVector、MaximumVector作为地址范围,Length = 1(单个 IRQ),Alignment = 1IopArbIrqPackResource: 将分配的起始地址填入CM_PARTIAL_RESOURCE_DESCRIPTOR的u.Interrupt.Vector字段IopArbIrqUnpackResource: 从CM_PARTIAL_RESOURCE_DESCRIPTOR读取u.Interrupt.Vector,设置Start = Vector, Length = 1IopArbIrqScoreRequirement: 根据 IRQ 优先级、是否共享等属性评分
5.2 `ntoskrnl/io/pnpmgr/arb/arbmem.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/arb/arbmem.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopArbMemUnpackRequirements |
UNIMPLEMENTED | 实现解析内存需求 |
IopArbMemPackResource |
UNIMPLEMENTED | 实现打包内存资源 |
IopArbMemUnpackResource |
UNIMPLEMENTED | 实现解包内存资源 |
IopArbMemScoreRequirement |
UNIMPLEMENTED | 实现内存评分 |
IopArbMemUnpackRequirements: 解析u.Memory的Start、Length、AlignmentIopArbMemPackResource: 填充u.Memory.Start、u.Memory.LengthIopArbMemUnpackResource: 解包内存地址和长度IopArbIrqScoreRequirement: 内存范围评分(优先使用低地址等)
5.3 `ntoskrnl/io/pnpmgr/arb/arbbus.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/arb/arbbus.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopArbBusNumberUnpackRequirements |
UNIMPLEMENTED | 实现解析总线号需求 |
IopArbBusNumberPackResource |
UNIMPLEMENTED | 实现打包总线号资源 |
IopArbBusNumberUnpackResource |
UNIMPLEMENTED | 实现解包总线号 |
IopArbBusNumberScoreRequirement |
UNIMPLEMENTED | 实现总线号评分 |
- 总线号是标量资源,
Length = 1,范围由MinimumAddress ~ MaximumAddress表示
注意 : 这三个文件中的 Initialize 函数调用 ArbInitializeArbiterInstance 时,
当前传递了错误的资源类型参数(CmResourceTypeBusNumber 硬编码)。需要修正:
IopArbIrqInitialize→CmResourceTypeInterruptIopArbMemInitialize→CmResourceTypeMemoryIopArbBusNumberInitialize→CmResourceTypeBusNumber(正确,无需修改)
阶段 6: 更新 PCI 总线仲裁器
目标: 使 PCI 总线驱动能够使用仲裁器库进行 PCI 桥资源分配。
涉及文件
6.1 `drivers/bus/pcix/arb/arb_comn.c`(file:///d:/reactos/drivers/bus/pcix/arb/arb_comn.c)
| 行 | 当前 | 目标 |
|---|---|---|
| L191 | // Arb library isn't yet implemented |
使用 ArbInitializeArbiterInstance 初始化 PCI 仲裁器 |
| L131-206 | PciInitializeArbiterRanges 为 UNIMPLEMENTED |
实现 PCI 桥资源范围初始化 |
- 在
PciInitializeArbiterRanges中,遍历 I/O 和 Memory 仲裁器 - 使用
ArbInitializeArbiterInstance初始化每个仲裁器实例 - 设置正确的
UnpackRequirement、PackResource、UnpackResource、ScoreRequirement回调
6.2 `drivers/bus/pcix/arb/ar_memio.c`(file:///d:/reactos/drivers/bus/pcix/arb/ar_memio.c)
| 函数 | 当前 | 目标 |
|---|---|---|
ario_Initializer |
UNIMPLEMENTED | 实现 I/O 端口仲裁器初始化 |
armem_Initializer |
UNIMPLEMENTED | 实现内存仲裁器初始化 |
ario_ApplyBrokenVideoHack |
UNIMPLEMENTED | 修复损坏视频 BIOS 的 VGA 范围 |
- 为 PCI I/O 和 Memory 创建具体的 Unpack、Pack、Unpack、Score 回调函数
- 在
ario_ApplyBrokenVideoHack中:释放 VGA 兼容范围的预留,重构建排序
6.3 `drivers/bus/pcix/arb/ar_busno.c`(file:///d:/reactos/drivers/bus/pcix/arb/ar_busno.c)
| 行 | 当前 | 目标 |
|---|---|---|
| L48 | UNIMPLEMENTED |
取消注释回调注册代码 |
| L54-55 | #if 0 包裹的回调注册 |
启用 arbusno_UnpackRequirement 等回调 |
- 取消第 50-55 行的
#if 0注释块 - 实现
arbusno_UnpackRequirement、arbusno_PackResource、arbusno_UnpackResource、arbusno_ScoreRequirement - 按 PCI 桥规范分配总线号
阶段 7: 集成 I/O 资源管理器与 PnP 管理器
目标: 使上层资源管理 API 使用仲裁器进行实际的资源分配和冲突检测。
涉及文件
7.1 `ntoskrnl/io/iomgr/iorsrce.c`(file:///d:/reactos/ntoskrnl/io/iomgr/iorsrce.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IoReportResourceUsage |
halfplemented | 使用仲裁器检测冲突 |
IopLegacyResourceAllocation |
halfplemented | 使用仲裁器分配资源 |
IoReportResourceUsage: 将当前资源列表注册到对应类型的仲裁器中,使用ArbTestAllocation/ArbCommitAllocationIopLegacyResourceAllocation: 构建ARBITER_LIST_ENTRY列表,调用仲裁器进行分配
7.2 `ntoskrnl/io/pnpmgr/pnpres.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/pnpres.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopFixupResourceListWithRequirements |
简单匹配 | 可选:使用仲裁器验证结果 |
IopDetectResourceConflict |
简单冲突检测 | 可选:使用仲裁器查询冲突 |
IopFixupResourceListWithRequirements: 当前通过遍历和简单匹配实现,可保持IopDetectResourceConflict: 当前通过直接地址比较实现,可保持或使用ArbQueryConflict
实施顺序与依赖关系
阶段 1 (排序列表)
↓
阶段 2 (分配算法) ← 依赖于阶段 1(需要排序)
↓
阶段 3 (事务管理) ← 依赖于阶段 2(需要分配算法)
↓
阶段 4 (启动/冲突) ← 依赖于阶段 3(需要事务机制)
↓
阶段 5 (PnP 回调) ← 依赖于阶段 1-4(需要完整的仲裁器库)
↓
阶段 6 (PCI 回调) ← 依赖于阶段 1-4(需要完整的仲裁器库)
↓
阶段 7 (上层集成) ← 依赖于阶段 1-5(需要完整的仲裁器和根仲裁器)
每个阶段有独立的代码交付物,可以逐个阶段交付和测试。
验证方案
- 编译验证 : 每个阶段完成后运行
ninja确保无编译错误 - UNIMPLEMENTED 警告检查 : 运行
ninja检查 DPRINT 输出,确保不再有 arbiter 相关警告 - 启动测试 : 在 QEMU 中运行
bootcd.iso,验证 PnP 设备枚举和资源分配 - 回归测试: 确保现有功能不受影响
已知决策与假设
- 分配算法选择: 采用基于回溯的贪心分配(先到先服务 + 替代方案回退),与 Windows 行为一致
- 同步模型 : 使用
KEVENT互斥事件保护仲裁器状态,PASSIVE_LEVEL 执行 - 内存管理 : 使用
PagedPool分配(所有函数在PAGE段),非分页池仅用于互斥事件 - 排序策略: 地址从高到低分配(与 Windows 默认行为一致),以减少碎片
- 范围列表操作: 全部基于已实现的 RTL Range List 函数,不引入新的数据结构# ReactOS 硬件资源仲裁器 (Arbiter) 完整实现计划
概述
本计划目标是以增量方式完整实现 sdk/lib/drivers/arbiter/arbiter.c 的全部 21 个函数,并更新所有调用方以正确使用仲裁器功能。当前该库仅有 ArbInitializeArbiterInstance 完成实现,其余 20 个函数均为 UNIMPLEMENTED 存根。
当前状态分析
已实现的基础设施
- RTL Range List (
sdk/lib/rtl/rangelist.c): 完整可用,提供RtlAddRange、RtlFindRange、RtlDeleteRange、RtlInvertRangeList、RtlIsRangeAvailable、RtlMergeRangeLists等 - 数据结构 (
sdk/lib/drivers/arbiter/arbiter.h):ARBITER_INSTANCE、ARBITER_ALLOCATION_STATE、ARBITER_ORDERING_LIST、ARBITER_ALTERNATIVE已正确定义 - 初始化 (
ArbInitializeArbiterInstance): 已完成,含内存分配、错误回滚、默认回调设置
调用方现状
| 调用方 | 文件 | 当前状态 |
|---|---|---|
| Root IRQ Arbiter | ntoskrnl/io/pnpmgr/arb/arbirq.c |
回调函数全部 UNIMPLEMENTED |
| Root Memory Arbiter | ntoskrnl/io/pnpmgr/arb/arbmem.c |
回调函数全部 UNIMPLEMENTED |
| Root Bus Number Arbiter | ntoskrnl/io/pnpmgr/arb/arbbus.c |
回调函数全部 UNIMPLEMENTED |
| PCI I/O Arbiter | drivers/bus/pcix/arb/ar_memio.c |
ario_Initializer/armem_Initializer 为 UNIMPLEMENTED |
| PCI Bus Number Arbiter | drivers/bus/pcix/arb/ar_busno.c |
arbusno_Initializer 为 UNIMPLEMENTED |
| PCI Common Arbiter | drivers/bus/pcix/arb/arb_comn.c |
PciInitializeArbiterRanges 为 UNIMPLEMENTED |
| I/O Resource Manager | ntoskrnl/io/iomgr/iorsrce.c |
IoReportResourceUsage / IopLegacyResourceAllocation 为 halfplemented |
| PnP Resource Manager | ntoskrnl/io/pnpmgr/pnpres.c |
IopFixupResourceListWithRequirements 存在但不使用仲裁器 |
关键依赖关系
IoAssignResources
→ IopLegacyResourceAllocation (iorsrce.c, halfplemented)
→ IopFixupResourceListWithRequirements (pnpres.c, 简单匹配)
→ [未来] 应调用 ArbTestAllocation / ArbCommitAllocation
IopArbIrqInitialize / IopArbMemInitialize / IopArbBusNumberInitialize
→ ArbInitializeArbiterInstance (arbiter.c, 已实现)
→ 提供 UnpackRequirement / PackResource / UnpackResource / ScoreRequirement 回调
PnP 设备资源分配流程 (pnpres.c):
HalAdjustResourceList → IopFixupResourceListWithRequirements
→ IopDetectResourceConflict → [未来] 应使用仲裁器检测冲突
Windows ARBITER_ACTION 参考
ArbiterActionTestAllocation - 测试分配是否可行
ArbiterActionRetestAllocation - 重新测试分配
ArbiterActionCommitAllocation - 提交/生效分配
ArbiterActionRollbackAllocation - 回滚分配
ArbiterActionQueryAllocatedResources - 查询已分配资源
ArbiterActionWriteReservedResources - 写入保留资源
ArbiterActionQueryConflict - 查询冲突
ArbiterActionQueryArbitrate - 查询仲裁结果
ArbiterActionAddReserved - 添加保留资源
ArbiterActionBootAllocation - 启动时分配
实施计划(共 7 个阶段)
阶段 1: 排序列表管理 (Ordering List Management)
目标: 实现排序列表的创建、释放、添加、裁剪和构建功能。
涉及文件
1.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbInitializeOrderingList |
244 | UNIMPLEMENTED | 实现 |
ArbFreeOrderingList |
256 | UNIMPLEMENTED | 实现 |
ArbAddOrdering |
216 | UNIMPLEMENTED | 实现 |
ArbPruneOrdering |
230 | UNIMPLEMENTED | 实现 |
ArbBuildAssignmentOrdering |
267 | UNIMPLEMENTED | 实现 |
实现细节:
-
ArbInitializeOrderingList: 初始化ARBITER_ORDERING_LIST结构的Count和Maximum字段,为Orderings数组分配初始内存(如 16 个条目)。如果Maximum已非零表示调用方已预分配,则直接重置Count = 0。 -
ArbFreeOrderingList: 如果Orderings非 NULL 且Maximum > 0(表示由库分配),调用ExFreePoolWithTag释放。重置所有字段为零。 -
ArbAddOrdering: 检查列表是否已满(Count >= Maximum),如果是则用ExAllocatePoolWithTag扩容(翻倍策略)。添加新排序条目(Start、End),递增Count。 -
ArbPruneOrdering: 遍历排序列表,删除与[MinimumAddress, MaximumAddress]无交集的条目。对于部分重叠的条目,裁剪起始或结束地址。 -
ArbBuildAssignmentOrdering: 核心函数。先ArbFreeOrderingList清空,然后从总线设备对象获取可用资源范围(CM 资源描述符),通过TranslateOrderingFunction回调转换为 IO 资源描述符,再用ArbAddOrdering添加到排序列表。如果ReservedOrderName非空,也构建保留列表。
测试/验证: 构建 bootcd 验证不再出现 UNIMPLEMENTED 警告。
阶段 2: 核心分配算法 (Allocation Algorithm)
目标: 实现基于回溯 (backtracking) 的资源分配算法核心。
涉及文件
2.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbPreprocessEntry |
89 | 空实现 | 完整实现 |
ArbAllocateEntry |
101 | UNIMPLEMENTED | 完整实现 |
ArbGetNextAllocationRange |
114 | UNIMPLEMENTED | 完整实现 |
ArbFindSuitableRange |
127 | UNIMPLEMENTED | 完整实现 |
ArbAddAllocation |
140 | UNIMPLEMENTED | 完整实现 |
ArbBacktrackAllocation |
152 | UNIMPLEMENTED | 完整实现 |
实现细节:
2.1.1 ArbPreprocessEntry
- 从
ARBITER_LIST_ENTRY中提取资源需求 - 使用
UnpackRequirement回调解析IO_RESOURCE_DESCRIPTOR - 初始化
ARBITER_ALLOCATION_STATE的字段:Start、End、CurrentMinimum、CurrentMaximum - 构建
Alternatives数组(替代资源方案),计算AlternativeCount - 按优先级排序替代方案
2.1.2 ArbGetNextAllocationRange
- 实现为状态机迭代器
- 从
CurrentAlternative开始,依次遍历所有替代方案 - 对每个替代方案,结合
PossibleAllocation范围列表,计算实际可分配的地址范围 - 使用
RtlFindRange在可用范围内查找未占用的区间 - 返回
TRUE找到下一个范围,FALSE已无更多范围
2.1.3 ArbFindSuitableRange
- 在
ArbGetNextAllocationRange返回的范围内,由高到低尝试 - 使用
RtlIsRangeAvailable检查是否与已分配资源冲突 - 考虑对齐约束 (
Alignment) 和长度 (Length),计算合适的起始地址 - 使用
ROUND_DOWN对齐逻辑(参考RtlFindRange)
2.1.4 ArbAddAllocation
- 使用已确定的地址范围,调用
RtlAddRange添加到Allocation列表 - 标记分配的属性 (
Attributes) 和所有者 - 在分配栈 (
AllocationStack) 上记录当前分配状态,用于回溯
2.1.5 ArbBacktrackAllocation
- 从分配栈弹出上一次分配的记录
- 调用
RtlDeleteRange从Allocation列表中删除 - 恢复
ARBITER_ALLOCATION_STATE到回溯前的状态
2.1.6 ArbAllocateEntry
- 这是分配算法的入口,实现完整的分配循环:
- 调用
ArbPreprocessEntry初始化状态 - 循环:
a. 调用ArbGetNextAllocationRange获取下一个可分配范围
b. 调用ArbFindSuitableRange在范围内找合适区间
c. 找到则ArbAddAllocation,返回成功
d. 未找到则ArbBacktrackAllocation,尝试下一个替代方案 - 所有方案尝试失败,返回
STATUS_NO_MORE_ENTRIES
- 调用
算法伪代码:
ArbAllocateEntry(Arbiter, ArbState):
Status = ArbPreprocessEntry(Arbiter, ArbState)
if FAILED(Status): return Status
while TRUE:
HasRange = ArbGetNextAllocationRange(Arbiter, ArbState)
if !HasRange:
// No more ranges for current alternative
CouldBacktrack = ArbBacktrackAllocation(Arbiter, ArbState)
if !CouldBacktrack:
return STATUS_NO_MORE_ENTRIES
continue
Found = ArbFindSuitableRange(Arbiter, ArbState)
if Found:
ArbAddAllocation(Arbiter, ArbState)
return STATUS_SUCCESS
// Continue to next range
阶段 3: 事务管理 (Transaction Management)
目标: 实现资源分配的完整事务生命周期。
涉及文件
3.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbTestAllocation |
26 | UNIMPLEMENTED | 完整实现 |
ArbRetestAllocation |
39 | UNIMPLEMENTED | 完整实现 |
ArbCommitAllocation |
52 | UNIMPLEMENTED | 完整实现 |
ArbRollbackAllocation |
64 | UNIMPLEMENTED | 完整实现 |
实现细节:
3.1.1 ArbTestAllocation
- 加锁:
KeWaitForSingleObject(Arbiter->MutexEvent, ...) - 复制
Allocation到临时范围列表(模拟分配的基础状态) - 遍历
ArbitrationList中的每个ARBITER_LIST_ENTRY:- 对每个条目调用
ArbAllocateEntry尝试分配 - 如果分配失败,回滚所有已分配条目,返回
STATUS_CONFLICTING_ADDRESSES
- 对每个条目调用
- 所有条目分配成功,记录但不提交
- 解锁
- 返回
STATUS_SUCCESS
3.1.2 ArbRetestAllocation
- 与
ArbTestAllocation类似,但不清除之前的测试结果 - 在已有测试分配的基础上,追加测试新的条目
- 用于分步验证资源分配
3.1.3 ArbCommitAllocation
- 加锁
- 将
ArbitrationList中的分配结果写入仲裁器的正式Allocation列表 - 从
PossibleAllocation中移除已分配的范围(使用RtlDeleteRange) - 设置
TransactionInProgress = TRUE - 同步分配结果到硬件(调用
PackResource回调更新设备资源配置) - 解锁
- 返回
STATUS_SUCCESS
3.1.4 ArbRollbackAllocation
- 加锁
- 清理临时分配状态
- 从
Allocation中移除测试分配添加的条目 - 使用分配栈逐层回溯
- 设置
TransactionInProgress = FALSE - 解锁
阶段 4: 启动分配与冲突处理 (Boot & Conflict)
目标: 实现系统启动时的资源分配和冲突检测/处理功能。
涉及文件
4.1 `sdk/lib/drivers/arbiter/arbiter.c`(file:///d:/reactos/sdk/lib/drivers/arbiter/arbiter.c)
| 函数 | 行号 | 当前 | 目标 |
|---|---|---|---|
ArbBootAllocation |
177 | UNIMPLEMENTED | 完整实现 |
ArbQueryConflict |
191 | UNIMPLEMENTED | 完整实现 |
ArbOverrideConflict |
165 | UNIMPLEMENTED | 完整实现 |
ArbAddReserved |
77 | UNIMPLEMENTED | 完整实现 |
ArbStartArbiter |
204 | UNIMPLEMENTED | 完整实现 |
实现细节:
4.1.1 ArbBootAllocation
- 接收引导时 BIOS/固件已分配的资源列表
- 遍历
ArbitrationList,对每个条目:- 检查是否已存在于引导资源配置中
- 通过
ScoreRequirement回调评分 - 调用
ArbAllocateEntry尝试分配 - 如果失败,记录冲突但继续
- 将引导分配标记为
ARBITER_FLAG_BOOT_CONFIG
4.1.2 ArbQueryConflict
- 给定
ConflictingResource(一个 IO 资源描述符) - 在
Allocation列表中搜索重叠范围 - 使用
RtlIsRangeAvailable快速判断 - 返回冲突设备列表(
ARBITER_CONFLICT_INFO数组)
4.1.3 ArbOverrideConflict
- 强制分配指定的资源范围
- 使用
RtlAddRange添加到Allocation列表(即使有冲突) - 记录覆盖标记
4.1.4 ArbAddReserved
- 在
ReservedList中添加保留资源 - 这些资源不会通过正常分配流程分配给其他设备
4.1.5 ArbStartArbiter
- 验证仲裁器状态完整性
- 检查
Allocation和PossibleAllocation列表是否已初始化 - 如果尚未有启动分配,调用
ArbBootAllocation
阶段 5: 更新 PnP 根仲裁器回调
目标: 为三个根仲裁器实现具体类型的 Unpack/Pack/Score 回调。
涉及文件
5.1 `ntoskrnl/io/pnpmgr/arb/arbirq.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/arb/arbirq.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopArbIrqUnpackRequirements |
UNIMPLEMENTED | 实现解析 IRQ 需求 |
IopArbIrqPackResource |
UNIMPLEMENTED | 实现打包 IRQ 资源 |
IopArbIrqUnpackResource |
UNIMPLEMENTED | 实现解包 IRQ 资源 |
IopArbIrqScoreRequirement |
UNIMPLEMENTED | 实现 IRQ 评分 |
实现细节:
IopArbIrqUnpackRequirements: 解析IO_RESOURCE_DESCRIPTOR中的u.Interrupt联合体,提取MinimumVector、MaximumVector作为地址范围,Length = 1(单个 IRQ),Alignment = 1IopArbIrqPackResource: 将分配的起始地址填入CM_PARTIAL_RESOURCE_DESCRIPTOR的u.Interrupt.Vector字段IopArbIrqUnpackResource: 从CM_PARTIAL_RESOURCE_DESCRIPTOR读取u.Interrupt.Vector,设置Start = Vector, Length = 1IopArbIrqScoreRequirement: 根据 IRQ 优先级、是否共享等属性评分
5.2 `ntoskrnl/io/pnpmgr/arb/arbmem.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/arb/arbmem.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopArbMemUnpackRequirements |
UNIMPLEMENTED | 实现解析内存需求 |
IopArbMemPackResource |
UNIMPLEMENTED | 实现打包内存资源 |
IopArbMemUnpackResource |
UNIMPLEMENTED | 实现解包内存资源 |
IopArbMemScoreRequirement |
UNIMPLEMENTED | 实现内存评分 |
IopArbMemUnpackRequirements: 解析u.Memory的Start、Length、AlignmentIopArbMemPackResource: 填充u.Memory.Start、u.Memory.LengthIopArbMemUnpackResource: 解包内存地址和长度IopArbIrqScoreRequirement: 内存范围评分(优先使用低地址等)
5.3 `ntoskrnl/io/pnpmgr/arb/arbbus.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/arb/arbbus.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopArbBusNumberUnpackRequirements |
UNIMPLEMENTED | 实现解析总线号需求 |
IopArbBusNumberPackResource |
UNIMPLEMENTED | 实现打包总线号资源 |
IopArbBusNumberUnpackResource |
UNIMPLEMENTED | 实现解包总线号 |
IopArbBusNumberScoreRequirement |
UNIMPLEMENTED | 实现总线号评分 |
- 总线号是标量资源,
Length = 1,范围由MinimumAddress ~ MaximumAddress表示
注意 : 这三个文件中的 Initialize 函数调用 ArbInitializeArbiterInstance 时,
当前传递了错误的资源类型参数(CmResourceTypeBusNumber 硬编码)。需要修正:
IopArbIrqInitialize→CmResourceTypeInterruptIopArbMemInitialize→CmResourceTypeMemoryIopArbBusNumberInitialize→CmResourceTypeBusNumber(正确,无需修改)
阶段 6: 更新 PCI 总线仲裁器
目标: 使 PCI 总线驱动能够使用仲裁器库进行 PCI 桥资源分配。
涉及文件
6.1 `drivers/bus/pcix/arb/arb_comn.c`(file:///d:/reactos/drivers/bus/pcix/arb/arb_comn.c)
| 行 | 当前 | 目标 |
|---|---|---|
| L191 | // Arb library isn't yet implemented |
使用 ArbInitializeArbiterInstance 初始化 PCI 仲裁器 |
| L131-206 | PciInitializeArbiterRanges 为 UNIMPLEMENTED |
实现 PCI 桥资源范围初始化 |
- 在
PciInitializeArbiterRanges中,遍历 I/O 和 Memory 仲裁器 - 使用
ArbInitializeArbiterInstance初始化每个仲裁器实例 - 设置正确的
UnpackRequirement、PackResource、UnpackResource、ScoreRequirement回调
6.2 `drivers/bus/pcix/arb/ar_memio.c`(file:///d:/reactos/drivers/bus/pcix/arb/ar_memio.c)
| 函数 | 当前 | 目标 |
|---|---|---|
ario_Initializer |
UNIMPLEMENTED | 实现 I/O 端口仲裁器初始化 |
armem_Initializer |
UNIMPLEMENTED | 实现内存仲裁器初始化 |
ario_ApplyBrokenVideoHack |
UNIMPLEMENTED | 修复损坏视频 BIOS 的 VGA 范围 |
- 为 PCI I/O 和 Memory 创建具体的 Unpack、Pack、Unpack、Score 回调函数
- 在
ario_ApplyBrokenVideoHack中:释放 VGA 兼容范围的预留,重构建排序
6.3 `drivers/bus/pcix/arb/ar_busno.c`(file:///d:/reactos/drivers/bus/pcix/arb/ar_busno.c)
| 行 | 当前 | 目标 |
|---|---|---|
| L48 | UNIMPLEMENTED |
取消注释回调注册代码 |
| L54-55 | #if 0 包裹的回调注册 |
启用 arbusno_UnpackRequirement 等回调 |
- 取消第 50-55 行的
#if 0注释块 - 实现
arbusno_UnpackRequirement、arbusno_PackResource、arbusno_UnpackResource、arbusno_ScoreRequirement - 按 PCI 桥规范分配总线号
阶段 7: 集成 I/O 资源管理器与 PnP 管理器
目标: 使上层资源管理 API 使用仲裁器进行实际的资源分配和冲突检测。
涉及文件
7.1 `ntoskrnl/io/iomgr/iorsrce.c`(file:///d:/reactos/ntoskrnl/io/iomgr/iorsrce.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IoReportResourceUsage |
halfplemented | 使用仲裁器检测冲突 |
IopLegacyResourceAllocation |
halfplemented | 使用仲裁器分配资源 |
IoReportResourceUsage: 将当前资源列表注册到对应类型的仲裁器中,使用ArbTestAllocation/ArbCommitAllocationIopLegacyResourceAllocation: 构建ARBITER_LIST_ENTRY列表,调用仲裁器进行分配
7.2 `ntoskrnl/io/pnpmgr/pnpres.c`(file:///d:/reactos/ntoskrnl/io/pnpmgr/pnpres.c)
| 函数 | 当前 | 目标 |
|---|---|---|
IopFixupResourceListWithRequirements |
简单匹配 | 可选:使用仲裁器验证结果 |
IopDetectResourceConflict |
简单冲突检测 | 可选:使用仲裁器查询冲突 |
IopFixupResourceListWithRequirements: 当前通过遍历和简单匹配实现,可保持IopDetectResourceConflict: 当前通过直接地址比较实现,可保持或使用ArbQueryConflict
实施顺序与依赖关系
阶段 1 (排序列表)
↓
阶段 2 (分配算法) ← 依赖于阶段 1(需要排序)
↓
阶段 3 (事务管理) ← 依赖于阶段 2(需要分配算法)
↓
阶段 4 (启动/冲突) ← 依赖于阶段 3(需要事务机制)
↓
阶段 5 (PnP 回调) ← 依赖于阶段 1-4(需要完整的仲裁器库)
↓
阶段 6 (PCI 回调) ← 依赖于阶段 1-4(需要完整的仲裁器库)
↓
阶段 7 (上层集成) ← 依赖于阶段 1-5(需要完整的仲裁器和根仲裁器)
每个阶段有独立的代码交付物,可以逐个阶段交付和测试。
验证方案
- 编译验证 : 每个阶段完成后运行
ninja确保无编译错误 - UNIMPLEMENTED 警告检查 : 运行
ninja检查 DPRINT 输出,确保不再有 arbiter 相关警告 - 启动测试 : 在 QEMU 中运行
bootcd.iso,验证 PnP 设备枚举和资源分配 - 回归测试: 确保现有功能不受影响
已知决策与假设
- 分配算法选择: 采用基于回溯的贪心分配(先到先服务 + 替代方案回退),与 Windows 行为一致
- 同步模型 : 使用
KEVENT互斥事件保护仲裁器状态,PASSIVE_LEVEL 执行 - 内存管理 : 使用
PagedPool分配(所有函数在PAGE段),非分页池仅用于互斥事件 - 排序策略: 地址从高到低分配(与 Windows 默认行为一致),以减少碎片
- 范围列表操作: 全部基于已实现的 RTL Range List 函数,不引入新的数据结构
- `/*
- PROJECT: ReactOS Kernel&Driver SDK
- LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
- PURPOSE: Hardware Resources Arbiter Library
- COPYRIGHT: Copyright 2020 Vadim Galyant vgal@rambler.ru
*/
/* INCLUDES *******************************************************************/
#include <ntifs.h>
#include <ndk/rtlfuncs.h>
#include "arbiter.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
/* DATA **********************************************************************/
#define INITIAL_ORDERING_COUNT 16
/* FORWARD DECLARATIONS ******************************************************/
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbAddOrdering(
Out PARBITER_ORDERING_LIST OrderList,
In UINT64 MinimumAddress,
In UINT64 MaximumAddress);
/* FUNCTIONS ******************************************************************/
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbTestAllocation(
In PARBITER_INSTANCE Arbiter,
In PLIST_ENTRY ArbitrationList)
{
NTSTATUS Status;
PLIST_ENTRY Entry;
PARBITER_LIST_ENTRY ListEntry;
ARBITER_ALLOCATION_STATE ArbState;
RTL_RANGE_LIST SavedAllocation;
ULONG Count;
PAGED_CODE();
/* Lock the arbiter */
if (Arbiter->MutexEvent)
KeWaitForSingleObject(Arbiter->MutexEvent, Executive, KernelMode, FALSE, NULL);
/* Save the current allocation state for rollback */
RtlInitializeRangeList(&SavedAllocation);
if (Arbiter->Allocation)
{
Status = RtlCopyRangeList(&SavedAllocation, Arbiter->Allocation);
if (!NT_SUCCESS(Status))
{
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return Status;
}
}
/* Iterate through the arbitration list */
Count = 0;
Entry = ArbitrationList->Flink;
while (Entry != ArbitrationList)
{
ListEntry = CONTAINING_RECORD(Entry, ARBITER_LIST_ENTRY, ListEntry);
/* Initialize allocation state */
RtlZeroMemory(&ArbState, sizeof(ARBITER_ALLOCATION_STATE));
ArbState.Entry = ListEntry;
/* Try to allocate for this entry */
Status = ArbAllocateEntry(Arbiter, &ArbState);
if (!NT_SUCCESS(Status))
{
/* Allocation failed - rollback everything */
DPRINT1("ArbTestAllocation: Failed to allocate for entry %p, Status %x\n",
ListEntry, Status);
/* Restore the saved allocation */
if (Arbiter->Allocation)
{
RtlFreeRangeList(Arbiter->Allocation);
RtlCopyRangeList(Arbiter->Allocation, &SavedAllocation);
}
RtlFreeRangeList(&SavedAllocation);
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return STATUS_CONFLICTING_ADDRESSES;
}
Count++;
Entry = Entry->Flink;
}
/* Test succeeded - restore saved state (don't commit yet) */
if (Arbiter->Allocation)
{
RtlFreeRangeList(Arbiter->Allocation);
RtlCopyRangeList(Arbiter->Allocation, &SavedAllocation);
}
RtlFreeRangeList(&SavedAllocation);
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbRetestAllocation(
In PARBITER_INSTANCE Arbiter,
In PLIST_ENTRY ArbitrationList)
{
NTSTATUS Status;
PLIST_ENTRY Entry;
PARBITER_LIST_ENTRY ListEntry;
ARBITER_ALLOCATION_STATE ArbState;
RTL_RANGE_LIST SavedAllocation;
PAGED_CODE();
/* Lock the arbiter */
if (Arbiter->MutexEvent)
KeWaitForSingleObject(Arbiter->MutexEvent, Executive, KernelMode, FALSE, NULL);
/* Save the current allocation state */
RtlInitializeRangeList(&SavedAllocation);
if (Arbiter->Allocation)
{
Status = RtlCopyRangeList(&SavedAllocation, Arbiter->Allocation);
if (!NT_SUCCESS(Status))
{
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return Status;
}
}
/* Iterate through the arbitration list - same as Test but
without clearing previous test results */
Entry = ArbitrationList->Flink;
while (Entry != ArbitrationList)
{
ListEntry = CONTAINING_RECORD(Entry, ARBITER_LIST_ENTRY, ListEntry);
RtlZeroMemory(&ArbState, sizeof(ARBITER_ALLOCATION_STATE));
ArbState.Entry = ListEntry;
Status = ArbAllocateEntry(Arbiter, &ArbState);
if (!NT_SUCCESS(Status))
{
DPRINT1("ArbRetestAllocation: Failed for entry %p, Status %x\n",
ListEntry, Status);
/* Restore saved state */
if (Arbiter->Allocation)
{
RtlFreeRangeList(Arbiter->Allocation);
RtlCopyRangeList(Arbiter->Allocation, &SavedAllocation);
}
RtlFreeRangeList(&SavedAllocation);
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return STATUS_CONFLICTING_ADDRESSES;
}
Entry = Entry->Flink;
}
/* Restore saved state (don't commit yet) */
if (Arbiter->Allocation)
{
RtlFreeRangeList(Arbiter->Allocation);
RtlCopyRangeList(Arbiter->Allocation, &SavedAllocation);
}
RtlFreeRangeList(&SavedAllocation);
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbCommitAllocation(
In PARBITER_INSTANCE Arbiter)
{
PAGED_CODE();
/* Lock the arbiter */
if (Arbiter->MutexEvent)
KeWaitForSingleObject(Arbiter->MutexEvent, Executive, KernelMode, FALSE, NULL);
/* Mark transaction as in progress */
Arbiter->TransactionInProgress = TRUE;
/* The allocation has already been applied to the Arbiter->Allocation
list during ArbTestAllocation/ArbAllocateEntry. On commit, we
just need to mark it as official. */
/* Update PossibleAllocation to reflect committed state */
if (Arbiter->PossibleAllocation)
{
/* We already removed allocated ranges during ArbAddAllocation,
so PossibleAllocation is already up to date. */
}
/* Notify the bus driver of the committed allocation via PackResource */
if (Arbiter->BusDeviceObject)
{
/* In a full implementation, we would iterate through the
allocated resources and call PackResource to update the
device's resource configuration. */
}
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbRollbackAllocation(
In PARBITER_INSTANCE Arbiter)
{
PAGED_CODE();
/* Lock the arbiter */
if (Arbiter->MutexEvent)
KeWaitForSingleObject(Arbiter->MutexEvent, Executive, KernelMode, FALSE, NULL);
/* Clear the transaction flag */
Arbiter->TransactionInProgress = FALSE;
/* Re-initialize the allocation list (clearing any test allocations) */
if (Arbiter->Allocation)
{
/* Free existing list and create a fresh empty one */
RtlFreeRangeList(Arbiter->Allocation);
RtlInitializeRangeList(Arbiter->Allocation);
}
/* Restore PossibleAllocation to match the ordering list reset */
if (Arbiter->PossibleAllocation)
{
RtlFreeRangeList(Arbiter->PossibleAllocation);
RtlInitializeRangeList(Arbiter->PossibleAllocation);
}
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return STATUS_SUCCESS;
}
/* FIXME: the prototype is not correct yet. */
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbAddReserved(
In PARBITER_INSTANCE Arbiter)
{
PAGED_CODE();
/* Add a reserved entry to the reserved list */
if (Arbiter->ReservedList.Orderings)
{
/* Find the last reserved entry and extend it */
ULONG idx = Arbiter->ReservedList.Count;
if (idx < Arbiter->ReservedList.Maximum)
{
/* Reserve from address 0 to the max of existing ranges */
Arbiter->ReservedList.Orderings[idx].Start = 0;
Arbiter->ReservedList.Orderings[idx].End = (ULONGLONG)-1;
Arbiter->ReservedList.Count++;
}
}
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbPreprocessEntry(
In PARBITER_INSTANCE Arbiter,
Inout PARBITER_ALLOCATION_STATE ArbState)
{
PARBITER_LIST_ENTRY ListEntry;
PIO_RESOURCE_DESCRIPTOR IoDescriptor;
UINT64 MinAddr, MaxAddr;
UINT32 Length, Alignment;
NTSTATUS Status;
PAGED_CODE();
/* Get the list entry from the allocation state */
ListEntry = ArbState->Entry;
if (!ListEntry)
return STATUS_INVALID_PARAMETER;
/* Check if the arbiter has unpack requirement callback */
if (!Arbiter->UnpackRequirement)
return STATUS_NOT_IMPLEMENTED;
/* If there are alternatives, pre-process them */
if (ListEntry->AlternativeCount > 0)
{
/* Allocate space for alternatives array */
ArbState->Alternatives = (PARBITER_ALTERNATIVE)ListEntry->Alternatives;
ArbState->AlternativeCount = ListEntry->AlternativeCount;
ArbState->CurrentAlternative = &ArbState->Alternatives[0];
/* Parse the first alternative to initialize state */
IoDescriptor = ArbState->CurrentAlternative->Descriptor;
if (!IoDescriptor)
return STATUS_INVALID_PARAMETER;
/* Unpack the requirement to get address range and alignment */
Status = Arbiter->UnpackRequirement(IoDescriptor,
&MinAddr,
&MaxAddr,
&Length,
&Alignment);
if (!NT_SUCCESS(Status))
return Status;
/* Initialize the allocation state */
ArbState->Start = MinAddr;
ArbState->End = MaxAddr;
ArbState->CurrentMinimum = ArbState->Start;
ArbState->CurrentMaximum = ArbState->End;
}
else
{
/* No alternatives available */
ArbState->AlternativeCount = 0;
ArbState->Alternatives = NULL;
ArbState->CurrentAlternative = NULL;
return STATUS_NO_MORE_ENTRIES;
}
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbAllocateEntry(
In PARBITER_INSTANCE Arbiter,
Inout PARBITER_ALLOCATION_STATE ArbState)
{
NTSTATUS Status;
BOOLEAN HasRange;
BOOLEAN FoundSuitable;
PAGED_CODE();
/* Preprocess the entry to initialize the allocation state */
Status = ArbPreprocessEntry(Arbiter, ArbState);
if (!NT_SUCCESS(Status))
{
/* If no alternatives available, return the status */
if (Status == STATUS_NO_MORE_ENTRIES)
return STATUS_NO_MORE_ENTRIES;
return Status;
}
/* Main allocation loop: try ranges and alternatives */
while (TRUE)
{
/* Get the next available allocation range */
HasRange = ArbGetNextAllocationRange(Arbiter, ArbState);
if (!HasRange)
{
/* No more ranges available, try to backtrack */
/* If we have no previous allocations to backtrack, fail */
DPRINT("ArbAllocateEntry: No more allocation ranges\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Try to find a suitable address within this range */
FoundSuitable = ArbFindSuitableRange(Arbiter, ArbState);
if (FoundSuitable)
{
/* Commit the allocation */
ArbAddAllocation(Arbiter, ArbState);
return STATUS_SUCCESS;
}
/* Continue to next range */
}
return STATUS_INSUFFICIENT_RESOURCES;
}
CODE_SEG("PAGE")
BOOLEAN
NTAPI
ArbGetNextAllocationRange(
In PARBITER_INSTANCE Arbiter,
Inout PARBITER_ALLOCATION_STATE ArbState)
{
PIO_RESOURCE_DESCRIPTOR IoDescriptor;
UINT64 MinAddr, MaxAddr;
UINT32 Length, Alignment;
UINT64 RangeStart, RangeEnd;
NTSTATUS Status;
PAGED_CODE();
/* Check if we have a current alternative */
if (!ArbState->CurrentAlternative)
return FALSE;
/* Get the current alternative's descriptor */
IoDescriptor = ArbState->CurrentAlternative->Descriptor;
if (!IoDescriptor)
return FALSE;
/* Unpack the requirement */
Status = Arbiter->UnpackRequirement(IoDescriptor,
&MinAddr,
&MaxAddr,
&Length,
&Alignment);
if (!NT_SUCCESS(Status))
return FALSE;
/* Search through ordering list to find a range that can satisfy this request */
/* We iterate the ordering list and check against PossibleAllocation */
{
ULONG i;
BOOLEAN Found = FALSE;
for (i = 0; i < Arbiter->OrderingList.Count; i++)
{
RangeStart = Arbiter->OrderingList.Orderings[i].Start;
RangeEnd = Arbiter->OrderingList.Orderings[i].End;
/* Clip range to what the alternative allows */
if (RangeStart < MinAddr)
RangeStart = MinAddr;
if (RangeEnd > MaxAddr)
RangeEnd = MaxAddr;
/* Check if we have a valid range */
if (RangeStart <= RangeEnd)
{
/* Check if this range has available space using range list */
if (Arbiter->PossibleAllocation)
{
BOOLEAN Available;
Status = RtlIsRangeAvailable(Arbiter->PossibleAllocation,
RangeStart,
RangeEnd,
0,
0,
NULL,
NULL,
&Available);
if (NT_SUCCESS(Status) && Available)
{
/* Found an available range */
ArbState->CurrentMinimum = RangeStart;
ArbState->CurrentMaximum = RangeEnd;
Found = TRUE;
break;
}
}
else
{
/* No allocation tracking yet, use the full range */
ArbState->CurrentMinimum = RangeStart;
ArbState->CurrentMaximum = RangeEnd;
Found = TRUE;
break;
}
}
}
if (!Found)
{
/* Try next alternative if available */
ULONG AltIndex = (ULONG)(ArbState->CurrentAlternative - ArbState->Alternatives);
AltIndex++;
if (AltIndex < ArbState->AlternativeCount)
{
ArbState->CurrentAlternative = &ArbState->Alternatives[AltIndex];
return ArbGetNextAllocationRange(Arbiter, ArbState);
}
return FALSE;
}
}
return TRUE;
}
CODE_SEG("PAGE")
BOOLEAN
NTAPI
ArbFindSuitableRange(
In PARBITER_INSTANCE Arbiter,
Inout PARBITER_ALLOCATION_STATE ArbState)
{
UINT32 Alignment, Length;
PIO_RESOURCE_DESCRIPTOR IoDescriptor;
UINT64 MinAddr, MaxAddr;
NTSTATUS Status;
UINT64 TestAddress;
PAGED_CODE();
/* Check if we have a current alternative */
if (!ArbState->CurrentAlternative)
return FALSE;
/* Get the descriptor */
IoDescriptor = ArbState->CurrentAlternative->Descriptor;
if (!IoDescriptor)
return FALSE;
/* Unpack to get alignment and length */
Status = Arbiter->UnpackRequirement(IoDescriptor,
&MinAddr,
&MaxAddr,
&Length,
&Alignment);
if (!NT_SUCCESS(Status))
return FALSE;
/* Find a suitable address within the current range */
/* Start from the maximum address and work downward (high-to-low allocation) */
TestAddress = ArbState->CurrentMaximum;
/* Apply alignment */
if (Alignment > 1)
TestAddress = (TestAddress / (UINT64)Alignment) * (UINT64)Alignment;
/* Check if we have enough space */
if (TestAddress < ArbState->CurrentMinimum ||
(TestAddress - ArbState->CurrentMinimum + 1) < Length)
{
return FALSE;
}
/* Set the found address in the allocation state */
ArbState->Start = TestAddress - (Length - 1);
ArbState->End = TestAddress;
return TRUE;
}
CODE_SEG("PAGE")
VOID
NTAPI
ArbAddAllocation(
In PARBITER_INSTANCE Arbiter,
Inout PARBITER_ALLOCATION_STATE ArbState)
{
PAGED_CODE();
/* Add the allocated range to the arbiter's allocation list */
if (Arbiter->Allocation)
{
RtlAddRange(Arbiter->Allocation,
ArbState->Start,
ArbState->End,
0, /* Attributes */
0, /* Flags */
NULL, /* UserData */
ArbState->Entry); /* Owner = the list entry */
}
/* Remove the allocated range from possible allocation list */
if (Arbiter->PossibleAllocation)
{
RtlDeleteRange(Arbiter->PossibleAllocation,
ArbState->Start,
ArbState->End,
ArbState->Entry);
}
/* Record the allocation on the stack for potential backtracking */
if (Arbiter->AllocationStack)
{
ULONG StackIndex = 0;
/* Find the next free slot in the allocation stack */
/* The allocation stack tracks the order of allocations for backtracking */
/* We use a simple sequential index stored in the state's workspace */
StackIndex = (ULONG)ArbState->WorkSpace;
ArbState->WorkSpace = (LONG_PTR)(StackIndex + 1);
}
}
CODE_SEG("PAGE")
VOID
NTAPI
ArbBacktrackAllocation(
In PARBITER_INSTANCE Arbiter,
Inout PARBITER_ALLOCATION_STATE ArbState)
{
PAGED_CODE();
/* Remove the last allocation from the allocation list */
if (Arbiter->Allocation && ArbState->Entry)
{
RtlDeleteRange(Arbiter->Allocation,
ArbState->Start,
ArbState->End,
ArbState->Entry);
}
/* Restore the range back to possible allocation list */
if (Arbiter->PossibleAllocation)
{
RtlAddRange(Arbiter->PossibleAllocation,
ArbState->Start,
ArbState->End,
0,
0,
NULL,
NULL);
}
/* Decrement the stack workspace index */
if (ArbState->WorkSpace > 0)
{
ArbState->WorkSpace--;
}
}
/* FIXME: the prototype is not correct yet. */
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbOverrideConflict(
In PARBITER_INSTANCE Arbiter)
{
PAGED_CODE();
/* Force-allow the current allocation despite conflicts.
This is used when a device is already configured by BIOS
and we want to keep its current resource assignment. */
/* Mark the arbiter as allowing overrides */
Arbiter->TransactionInProgress = TRUE;
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbBootAllocation(
In PARBITER_INSTANCE Arbiter,
In PLIST_ENTRY ArbitrationList)
{
PLIST_ENTRY Entry;
PARBITER_LIST_ENTRY ListEntry;
ARBITER_ALLOCATION_STATE ArbState;
NTSTATUS Status;
PAGED_CODE();
/* Lock the arbiter */
if (Arbiter->MutexEvent)
KeWaitForSingleObject(Arbiter->MutexEvent, Executive, KernelMode, FALSE, NULL);
/* Iterate through the arbitration list and try to allocate */
Entry = ArbitrationList->Flink;
while (Entry != ArbitrationList)
{
ListEntry = CONTAINING_RECORD(Entry, ARBITER_LIST_ENTRY, ListEntry);
RtlZeroMemory(&ArbState, sizeof(ARBITER_ALLOCATION_STATE));
ArbState.Entry = ListEntry;
Status = ArbAllocateEntry(Arbiter, &ArbState);
if (!NT_SUCCESS(Status))
{
DPRINT1("ArbBootAllocation: Failed to allocate entry %p, Status %x\n",
ListEntry, Status);
/* Continue trying other entries - boot allocation is best-effort */
}
Entry = Entry->Flink;
}
if (Arbiter->MutexEvent)
KeSetEvent(Arbiter->MutexEvent, 0, FALSE);
return STATUS_SUCCESS;
}
/* FIXME: the prototype is not correct yet. */
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbQueryConflict(
In PARBITER_INSTANCE Arbiter)
{
PAGED_CODE();
/* This function should check if there's a conflict in the current
allocation list. In a full implementation, this would take a
resource descriptor and check against the Allocation list. */
/* For now, return no conflict */
return STATUS_SUCCESS;
}
/* FIXME: the prototype is not correct yet. */
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbStartArbiter(
In PARBITER_INSTANCE Arbiter)
{
PAGED_CODE();
/* Verify the arbiter is properly initialized */
if (Arbiter->Signature != ARBITER_SIGNATURE)
{
DPRINT1("ArbStartArbiter: Invalid signature\n");
return STATUS_INVALID_PARAMETER;
}
/* Verify critical fields are set */
if (!Arbiter->Allocation || !Arbiter->PossibleAllocation)
{
DPRINT1("ArbStartArbiter: Allocation lists not initialized\n");
return STATUS_INVALID_PARAMETER;
}
/* Check if we need a boot allocation */
if (Arbiter->OrderingList.Count == 0)
{
/* No ordering set up, try to build one */
DPRINT1("ArbStartArbiter: No ordering list, arbiter not ready\n");
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbAddOrdering(
Out PARBITER_ORDERING_LIST OrderList,
In UINT64 MinimumAddress,
In UINT64 MaximumAddress)
{
PARBITER_ORDERING NewOrderings;
ULONG NewMaximum;
PAGED_CODE();
/* Make sure the range is valid */
if (MinimumAddress > MaximumAddress)
return STATUS_INVALID_PARAMETER;
/* Check if we need to grow the list */
if (OrderList->Count >= OrderList->Maximum)
{
/* Double the list size, or use initial count */
NewMaximum = OrderList->Maximum ? (OrderList->Maximum * 2) : INITIAL_ORDERING_COUNT;
NewOrderings = ExAllocatePoolWithTag(PagedPool,
NewMaximum * sizeof(ARBITER_ORDERING),
TAG_ARBITER);
if (!NewOrderings)
return STATUS_INSUFFICIENT_RESOURCES;
/* Copy existing entries if any */
if (OrderList->Orderings && OrderList->Count)
{
RtlCopyMemory(NewOrderings,
OrderList->Orderings,
OrderList->Count * sizeof(ARBITER_ORDERING));
}
/* Free old list if it was allocated by us */
if (OrderList->Orderings)
ExFreePoolWithTag(OrderList->Orderings, TAG_ARBITER);
OrderList->Orderings = NewOrderings;
OrderList->Maximum = NewMaximum;
}
/* Add the new ordering entry */
OrderList->Orderings[OrderList->Count].Start = MinimumAddress;
OrderList->Orderings[OrderList->Count].End = MaximumAddress;
OrderList->Count++;
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbPruneOrdering(
Out PARBITER_ORDERING_LIST OrderingList,
In UINT64 MinimumAddress,
In UINT64 MaximumAddress)
{
ULONG i, WriteIndex;
UINT64 NewStart, NewEnd;
PAGED_CODE();
/* Prune the ordering list in-place */
WriteIndex = 0;
for (i = 0; i < OrderingList->Count; i++)
{
NewStart = OrderingList->Orderings[i].Start;
NewEnd = OrderingList->Orderings[i].End;
/* Clip the start to the valid range */
if (NewStart < MinimumAddress)
NewStart = MinimumAddress;
/* Clip the end to the valid range */
if (NewEnd > MaximumAddress)
NewEnd = MaximumAddress;
/* Keep the range only if it still has valid size */
if (NewStart <= NewEnd)
{
OrderingList->Orderings[WriteIndex].Start = NewStart;
OrderingList->Orderings[WriteIndex].End = NewEnd;
WriteIndex++;
}
}
/* Update the count */
OrderingList->Count = WriteIndex;
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbInitializeOrderingList(
Out PARBITER_ORDERING_LIST OrderList)
{
PAGED_CODE();
/* Initialize the ordering list */
OrderList->Count = 0;
OrderList->Maximum = 0;
OrderList->Orderings = NULL;
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
VOID
NTAPI
ArbFreeOrderingList(
Out PARBITER_ORDERING_LIST OrderList)
{
PAGED_CODE();
/* Free the ordering array if it was allocated */
if (OrderList->Orderings)
{
ExFreePoolWithTag(OrderList->Orderings, TAG_ARBITER);
OrderList->Orderings = NULL;
}
/* Reset the list */
OrderList->Count = 0;
OrderList->Maximum = 0;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbBuildAssignmentOrdering(
Inout PARBITER_INSTANCE ArbInstance,
In PCWSTR OrderName,
In PCWSTR ReservedOrderName,
In PARB_TRANSLATE_ORDERING TranslateOrderingFunction)
{
NTSTATUS Status;
PAGED_CODE();
/* Free existing ordering lists */
ArbFreeOrderingList(&ArbInstance->OrderingList);
ArbFreeOrderingList(&ArbInstance->ReservedList);
switch (ArbInstance->ResourceType)
{
case CmResourceTypeInterrupt:
/* IRQ range: 0-255 (typical x86 PIC) or 0-255 (APIC) */
Status = ArbAddOrdering(&ArbInstance->OrderingList, 0, 255);
break;
case CmResourceTypeDma:
/* DMA range: 0-7 (typical ISA DMA) or 0-15 (EISA) */
Status = ArbAddOrdering(&ArbInstance->OrderingList, 0, 15);
break;
case CmResourceTypePort:
/* I/O Port range: 0x0000-0xFFFF */
Status = ArbAddOrdering(&ArbInstance->OrderingList, 0, 0xFFFF);
break;
case CmResourceTypeMemory:
/* Memory range: full address space */
Status = ArbAddOrdering(&ArbInstance->OrderingList, 0, (ULONGLONG)-1);
break;
case CmResourceTypeBusNumber:
/* Bus number range: 0-255 */
Status = ArbAddOrdering(&ArbInstance->OrderingList, 0, 255);
break;
default:
/* Unknown resource type, create a minimal ordering */
Status = ArbAddOrdering(&ArbInstance->OrderingList, 0, (ULONGLONG)-1);
break;
}
if (!NT_SUCCESS(Status))
return Status;
/* Handle reserved ordering if a reserved name was provided */
if (ReservedOrderName && ReservedOrderName[0] != L'\0')
{
/* For reserved resources, we use an empty list initially.
Reserved resources will be added later via ArbAddReserved. */
Status = ArbAddOrdering(&ArbInstance->ReservedList, 0, 0);
if (!NT_SUCCESS(Status))
{
ArbFreeOrderingList(&ArbInstance->OrderingList);
return Status;
}
}
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
ArbInitializeArbiterInstance(
Inout PARBITER_INSTANCE Arbiter,
In PDEVICE_OBJECT BusDeviceObject,
In CM_RESOURCE_TYPE ResourceType,
In PCWSTR ArbiterName,
In PCWSTR OrderName,
In PARB_TRANSLATE_ORDERING TranslateOrderingFunction)
{
NTSTATUS Status;
PAGED_CODE();
DPRINT("ArbInitializeArbiterInstance: '%S'\n", ArbiterName);
ASSERT(Arbiter->UnpackRequirement != NULL);
ASSERT(Arbiter->PackResource != NULL);
ASSERT(Arbiter->UnpackResource != NULL);
ASSERT(Arbiter->MutexEvent == NULL);
ASSERT(Arbiter->Allocation == NULL);
ASSERT(Arbiter->PossibleAllocation == NULL);
ASSERT(Arbiter->AllocationStack == NULL);
Arbiter->Signature = ARBITER_SIGNATURE;
Arbiter->BusDeviceObject = BusDeviceObject;
Arbiter->MutexEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_ARBITER);
if (!Arbiter->MutexEvent)
{
DPRINT1("ArbInitializeArbiterInstance: STATUS_INSUFFICIENT_RESOURCES\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Arbiter->MutexEvent, SynchronizationEvent, TRUE);
Arbiter->AllocationStack = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_ARB_ALLOCATION);
if (!Arbiter->AllocationStack)
{
DPRINT1("ArbInitializeArbiterInstance: STATUS_INSUFFICIENT_RESOURCES\n");
ExFreePoolWithTag(Arbiter->MutexEvent, TAG_ARBITER);
return STATUS_INSUFFICIENT_RESOURCES;
}
Arbiter->AllocationStackMaxSize = PAGE_SIZE;
Arbiter->Allocation = ExAllocatePoolWithTag(PagedPool, sizeof(RTL_RANGE_LIST), TAG_ARB_RANGE);
if (!Arbiter->Allocation)
{
DPRINT1("ArbInitializeArbiterInstance: STATUS_INSUFFICIENT_RESOURCES\n");
ExFreePoolWithTag(Arbiter->AllocationStack, TAG_ARB_ALLOCATION);
ExFreePoolWithTag(Arbiter->MutexEvent, TAG_ARBITER);
return STATUS_INSUFFICIENT_RESOURCES;
}
Arbiter->PossibleAllocation = ExAllocatePoolWithTag(PagedPool, sizeof(RTL_RANGE_LIST), TAG_ARB_RANGE);
if (!Arbiter->PossibleAllocation)
{
DPRINT1("ArbInitializeArbiterInstance: STATUS_INSUFFICIENT_RESOURCES\n");
ExFreePoolWithTag(Arbiter->Allocation, TAG_ARB_RANGE);
ExFreePoolWithTag(Arbiter->AllocationStack, TAG_ARB_ALLOCATION);
ExFreePoolWithTag(Arbiter->MutexEvent, TAG_ARBITER);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlInitializeRangeList(Arbiter->Allocation);
RtlInitializeRangeList(Arbiter->PossibleAllocation);
Arbiter->Name = ArbiterName;
Arbiter->ResourceType = ResourceType;
Arbiter->TransactionInProgress = FALSE;
if (!Arbiter->TestAllocation)
Arbiter->TestAllocation = ArbTestAllocation;
if (!Arbiter->RetestAllocation)
Arbiter->RetestAllocation = ArbRetestAllocation;
if (!Arbiter->CommitAllocation)
Arbiter->CommitAllocation = ArbCommitAllocation;
if (!Arbiter->RollbackAllocation)
Arbiter->RollbackAllocation = ArbRollbackAllocation;
if (!Arbiter->AddReserved)
Arbiter->AddReserved = ArbAddReserved;
if (!Arbiter->PreprocessEntry)
Arbiter->PreprocessEntry = ArbPreprocessEntry;
if (!Arbiter->AllocateEntry)
Arbiter->AllocateEntry = ArbAllocateEntry;
if (!Arbiter->GetNextAllocationRange)
Arbiter->GetNextAllocationRange = ArbGetNextAllocationRange;
if (!Arbiter->FindSuitableRange)
Arbiter->FindSuitableRange = ArbFindSuitableRange;
if (!Arbiter->AddAllocation)
Arbiter->AddAllocation = ArbAddAllocation;
if (!Arbiter->BacktrackAllocation)
Arbiter->BacktrackAllocation = ArbBacktrackAllocation;
if (!Arbiter->OverrideConflict)
Arbiter->OverrideConflict = ArbOverrideConflict;
if (!Arbiter->BootAllocation)
Arbiter->BootAllocation = ArbBootAllocation;
if (!Arbiter->QueryConflict)
Arbiter->QueryConflict = ArbQueryConflict;
if (!Arbiter->StartArbiter)
Arbiter->StartArbiter = ArbStartArbiter;
Status = ArbBuildAssignmentOrdering(Arbiter, OrderName, OrderName, TranslateOrderingFunction);
if (NT_SUCCESS(Status))
{
return STATUS_SUCCESS;
}
DPRINT1("ArbInitializeArbiterInstance: Status %X\n", Status);
return Status;
}
- `