① RIS 形式语言与数据模型

RIS(Register Interaction Sequence,寄存器交互序列)是 reharness 的核心产物。实现位于 src/extractor/formal.py(表达式代数 + Display 语法)与 src/extractor/formalize.py(扁平 Op 流 → 嵌套 FormalRIS)。

1.1 形式文法

直接引用 formal.py 模块 docstring 中的定义:

Expr   = Const | Var | BinOp{op,left,right} | Ite{guard,then,else}
       | Bits{hi,lo,expr} | Top
RegAddr= Fixed{base,offset} | Symbolic{device,register} | Computed(Expr)
RISOp  = Read | Write | ReadModifyWrite | TransactionRead
       | TransactionWrite | TransactionUpdate | StateRead | StateWrite
       | OutputWrite | Return | Delay | Cond | Seq | Loop
FormalRIS = {driver, version, modules[], register_map[], metadata}
设计要点:表达式域刻意很小(Const/Var/BinOp/Ite/Bits/Top),Top 表示「无法静态解析」,是 strict readiness 的显式阻塞器 —— 系统宁可拒绝也不猜。

1.2 表达式代数的实现(formal.py)

parse_expr —— 尽力而为的 C 表达式解析

把提取器拿到的值/条件字符串解析成 Expr dict。关键实现决策(按优先级从低到高逐层切分):

BINOPS = ["==", "!=", "<=", ">=", "&&", "||", "<<", ">>", "<", ">",
          "|", "^", "&", "+", "-", "*", "/", "%"]

simplify_expr —— 常量折叠

对 BinOp 双常量的 19 种运算就地求值(& 0xFFFFFFFFFFFFFFFF 防溢出);Ite 守卫为常量时直接选边,then/else 相同则合并;Bits 常量切片折叠。符号项(Var)永不触碰 —— 保证「不改变符号语义的折叠」。

expr_display —— 回写成人类可读

Formal Expr → 文本( 表示 Top),用于 .ris 文件输出。

1.3 地址分类:不伪装的精度哲学

分类含义示例(edu)
Symbolic可静态命名的寄存器访问priv->mmio.IO_IRQ_STATUS(宏解析后归入 register_map)
Fixed常量偏移地址priv->mmio + 0x0
Computed运行时计算地址,保留完整动态 offset 表达式priv->mmio + *off[0x0](edu_read 的 file offset 寻址)
对应 formalize.py_common_fieldsaddress_precision = symbolic | fixed | computed | unknown(Computed 内含 Top 时降级为 unknown)。矩阵里 366 symbolic / 64 fixed / 41 computed 的统计就是这么来的,绝不把运行时索引伪造成「100% symbolic」。

1.4 操作类型与精度字段

Op语义
Readvar := R(width, addr),记录 LHS 变量名(op.var
WriteW(width, addr) = expr
ReadModifyWriteRMW(width, addr) = transform,保留 read_var —— 由 readl→modify→writel 数据流模式合成
Transaction*regmap / I2C/SMBus / MFD 事务,显式区分 target、selector、scalar/buffer payload,不伪装成 MMIO
StateRead/Write驱动私有状态字段(如 pl061->csave_regs.*
Cond / Loop / Seq结构化控制流:Cond{guard, then_ops, else_ops}Loop{guard, body}

每个叶子 op 都带五个审计字段(formalize.py: _common_fields):

{
  "op_id": "op_12",                    # 全局唯一,生成契约的锚点
  "evidence": {...},                   # 源码位置/调用栈/访问域
  "reliability": "Exact|Conservative|Unknown|Unsupported",
  "address_precision": "symbolic",     # symbolic|fixed|computed|unknown
  "value_precision": "exact|unknown",  # 值表达式含 Top 则 unknown
  "path_precision": "unconditional|syntactic",  # 是否有 cond_stack
  "access_domain": "mmio|regmap|i2c|mfd|source_state|unsupported_*"
}

reliability 的推导规则:非 MMIO 域 → Unsupported;地址或值 unknown → Unknown;路径是语法级条件 → Conservative;全精确 → Exact

1.5 真实示例:edu.ris(QEMU 教学设备,全量)

这是 artifacts/output/edu/edu.ris 的完整内容 —— 最小但五脏俱全:

driver edu v0.1.0 {
  module edu_irq_handler {
    status := R(B4, priv->mmio.IO_IRQ_STATUS) -- Interrupt
    W(B4, priv->mmio.IO_IRQ_ACK) = status -- Interrupt
  }
  module edu_read {
    val := R(B4, priv->mmio + *off[0x0]) -- Status
  }
  module edu_write {
    W(B4, priv->mmio + *off[0x0]) = val -- Config
  }
  module edu_pci_probe {
    dev_id := R(B4, priv->mmio.IO_ID) -- Status
  }
}

1.6 真实示例:gpio-pl061.ris(丰富语法)

节选 artifacts/output/portable-gpio-pl061/gpio-pl061.ris 讲解三种高级形态:

  module pl061_get_direction {
    IF (readb(pl061->base + GPIODIR) & (0x1 << offset)) {   -- Cond:条件读
      r1 := R(B1, pl061->base.GPIODIR) -- Config
    }
  }
  module pl061_direction_input {
    gpiodir := R(B1, pl061->base.GPIODIR) -- Config
    RMW(B1, pl061->base.GPIODIR) = gpiodir -- Config   -- 读改写合成
  }
  module pl061_irq_type {
    gpioiev := R(B1, pl061->base.GPIOIEV) -- Status
    gpiois  := R(B1, pl061->base.GPIOIS)  -- Status
    RMW(B1, pl061->base.GPIOIS)  = gpiois  -- Config
    RMW(B1, pl061->base.GPIOIBE) = gpioibe -- Config
    RMW(B1, pl061->base.GPIOIEV) = gpioiev -- Config
  }
  module pl061_suspend {
    pl061->csave_regs.gpio_dir := R(B1, pl061->base.GPIODIR) -- Config
    ...
  }
  module pl061_resume {
    W(B1, pl061->base.GPIOIS) = pl061->csave_regs.gpio_is -- Config
    ...
  }

1.7 结构化输出与遍历

下一章预告:这些 .ris 是怎么从 C 源码里挖出来的?下一章深入提取器的 AST 模型、调用图内联、数据流/污点三件套。