如何使用frama-c Eva插件或WP-RTE验证读写硬件内存映射寄存器(mmio)的代码?

时间:2018-10-08 18:23:15

标签: frama-c

我找到的最接近答案可能与Eva插件的-absolute-valid-range有关,是吗?我是否必须提出读/写ACSL谓词才能进行虚拟读/写?

示例代码:

#include <stdint.h>

#define BASE_ADDR 0x0e000000
#define BASE_LIMIT 0x0e001000
#define TEST_REG 0x10

/*@ requires BASE_ADDR <= addr < BASE_LIMIT;
  @ assigns \nothing;
 */
static inline uint32_t mmio_read32(volatile uintptr_t addr)
{
    volatile uint32_t *ptr = (volatile uint32_t *)addr;
    return *ptr;
}
/*@
  @ requires 0 <= offset <= 0x1000;
  @ assigns \nothing;
 */
static inline uint32_t read32(uintptr_t offset)
{
    return mmio_read32((uintptr_t)BASE_ADDR + offset);
}

void main(){
    uint32_t test;
    test = read32(TEST_REG);
    return;
}

Frama-c命令和输出:

[frama -absolute-valid-range 0x0e000000-0x0e001000 -wp mmio2.c
[kernel] Parsing mmio2.c (with preprocessing)
[wp] Warning: Missing RTE guards
[wp] 6 goals scheduled
[wp] [Alt-Ergo] Goal typed_read32_call_mmio_read32_pre : Unknown (Qed:4ms) (51ms)
[wp] Proved goals:    5 / 6
   Qed:             5
   Alt-Ergo:        0  (unknown: 1)][1]

如何实现目标“ typed_read32_call_mmio_read32_pre”?或者是预期的?

1 个答案:

答案 0 :(得分:1)

证明失败的事实与两个独立的问题有关,但它们都与使用绝对地址无关。

首先,由于mmio_read32的参数被标记为volatile,因此WP认为其值可以是任何值。特别是,在评估offset时,对addr进行的假设均不成立。通过查看生成的目标,您可以在GUI中看到这一点(在底部的WP Goals标签中,双击Script冒号和失败的证明尝试行):

Goal Instance of 'Pre-condition'
 (call 'mmio_read32'):
Assume {
  Type: is_uint32(offset_0).
  (* Pre-condition *)
  Have: (0 <= offset_0) /\ (offset_0 <= 4095).
}
Prove: (234881024 <= w) /\ (w_1 <= 234885119).

ww_1对应于对addr易失内容的两次读取访问。我不确定您是否真的打算将addr参数设置为volatile(而不是指向volatile位置的非volatile指针),因为这将需要一个非常奇怪的执行环境。

假设volatile的声明中不应该包含addr限定词,剩下的问题是offset中对read32的约束太弱了:应该以严格的不等式阅读offset < 0x1000(或将mmio_read32的先决条件设为非严格条件,但这再次很少见)。

关于ACSL中有关物理地址和易失性的最初问题(请参见the manual的2.12.1节),您具有一个特定的volatile子句,可用于指定(C,通常为幻影)函数代表对volatile位置的读写访问。不幸的是,目前只能通过非公开发行的插件来访问这些条款。

恐怕如果您想在具有物理地址的代码上使用WP,则确实确实需要使用编码(例如,使用适当大小的Ghost数组)和/或使用适当功能对易失性访问进行建模。