зеркало из https://github.com/microsoft/Komodo.git
391 строка
11 KiB
Plaintext
391 строка
11 KiB
Plaintext
include {:verbatim} "ARMspartan.dfy"
|
|
|
|
var{:state ok()} ok:bool;
|
|
var{:state mem()} mem:memmap;
|
|
var{:state globals()} globals:globalsmap;
|
|
|
|
var{:state osp()} sp:word;
|
|
var{:state olr()} lr:word;
|
|
var{:state reg(R0)} r0:word;
|
|
var{:state reg(R1)} r1:word;
|
|
var{:state reg(R2)} r2:word;
|
|
var{:state reg(R3)} r3:word;
|
|
var{:state reg(R4)} r4:word;
|
|
var{:state reg(R5)} r5:word;
|
|
var{:state reg(R6)} r6:word;
|
|
var{:state reg(R7)} r7:word;
|
|
var{:state reg(R8)} r8:word;
|
|
var{:state reg(R9)} r9:word;
|
|
var{:state reg(R10)} r10:word;
|
|
var{:state reg(R11)} r11:word;
|
|
var{:state reg(R12)} r12:word;
|
|
|
|
var{:state reg(SP(User))} sp_usr:int;
|
|
var{:state reg(SP(FIQ))} sp_fiq:int;
|
|
var{:state reg(SP(IRQ))} sp_irq:int;
|
|
var{:state reg(SP(Supervisor))} sp_svc:int;
|
|
var{:state reg(SP(Abort))} sp_abt:int;
|
|
var{:state reg(SP(Undefined))} sp_und:int;
|
|
var{:state reg(SP(Monitor))} sp_mon:int;
|
|
|
|
var{:state reg(LR(User))} lr_usr:int;
|
|
var{:state reg(LR(FIQ))} lr_fiq:int;
|
|
var{:state reg(LR(IRQ))} lr_irq:int;
|
|
var{:state reg(LR(Supervisor))} lr_svc:int;
|
|
var{:state reg(LR(Abort))} lr_abt:int;
|
|
var{:state reg(LR(Undefined))} lr_und:int;
|
|
var{:state reg(LR(Monitor))} lr_mon:int;
|
|
|
|
var{:state sreg(spsr(FIQ))} spsr_fiq:int;
|
|
var{:state sreg(spsr(IRQ))} spsr_irq:int;
|
|
var{:state sreg(spsr(Supervisor))} spsr_svc:int;
|
|
var{:state sreg(spsr(Abort))} spsr_abt:int;
|
|
var{:state sreg(spsr(Undefined))} spsr_und:int;
|
|
var{:state sreg(spsr(Monitor))} spsr_mon:int;
|
|
var{:state sreg(cpsr)} cpsr:int;
|
|
|
|
#verbatim
|
|
function MaybeUpdateOk(s:va_state, r:va_state) : va_state
|
|
{
|
|
if !(s.ok && r.ok) then s.(ok := false) else r
|
|
}
|
|
#endverbatim
|
|
|
|
procedure operator(:=) (out operand dst:word, operand src:word) := MOV;
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(ADD(dst, src1, src2))}
|
|
ADD(out operand dst:word, operand src1:word, operand src2:word)
|
|
requires
|
|
isUInt32(src1 + src2);
|
|
ensures
|
|
dst == old(src1 + src2);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
reveal TruncateWord;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(ADD(dst, src1, src2))}
|
|
ADDWrap(out operand dst:word, operand src1:word, operand src2:word)
|
|
ensures
|
|
dst == TruncateWord(old(src1 + src2));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(ADD(dst, src1, OShift(GetProbableReg(src2), shift)))}
|
|
ADDWrapShift(out operand dst:word, operand src1:word, operand src2:snd, inline shift:Shift)
|
|
ensures
|
|
dst == TruncateWord(old(src1 + EvalShift(old(src2), shift)));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(SUB(dst, src1, src2))}
|
|
SUB(out operand dst:word, operand src1:word, operand src2:word)
|
|
requires
|
|
isUInt32(src1 - src2);
|
|
ensures
|
|
dst == old(src1 - src2);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(MUL(dst, src1, src2))}
|
|
MUL(out operand dst:word, operand src1:reg, operand src2:reg)
|
|
requires
|
|
isUInt32(src1 * src2);
|
|
ensures
|
|
dst == old(src1 * src2);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(UDIV(dst, src1, src2))}
|
|
UDIV(out operand dst:word, operand src1:word, operand src2:word)
|
|
requires
|
|
src2 > 0;
|
|
isUInt32(src1 / src2);
|
|
ensures
|
|
dst == old(src1 / src2);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(AND(dst, src1, src2))}
|
|
AND(out operand dst:word, operand src1:word, operand src2:word)
|
|
ensures
|
|
dst == old(BitwiseAnd(src1, src2));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(ORR(dst, src1, src2))}
|
|
ORR(out operand dst:word, operand src1:word, operand src2:word)
|
|
ensures
|
|
dst == old(BitwiseOr(src1, src2));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(EOR(dst, src1, src2))}
|
|
EOR(out operand dst:word, operand src1:word, operand src2:word)
|
|
ensures
|
|
dst == old(BitwiseXor(src1, src2));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(EOR(dst, src1, OShift(GetProbableReg(src2), shift)))}
|
|
EORShift(out operand dst:word, operand src1:word, operand src2:snd, inline shift:Shift)
|
|
ensures
|
|
dst == BitwiseXor(old(src1), EvalShift(old(src2), shift));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(LSL(dst, src1, src2))}
|
|
LSL(out operand dst:word, operand src1:word, operand src2:word)
|
|
requires
|
|
0 <= src2 < 32;
|
|
requires {:refined false}
|
|
@src2 is OConst;
|
|
ensures
|
|
dst == old(LeftShift(src1, src2));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(LSR(dst, src1, src2))}
|
|
LSR(out operand dst:word, operand src1:word, operand src2:word)
|
|
requires
|
|
0 <= src2 < 32;
|
|
requires {:refined false}
|
|
@src2 is OConst;
|
|
ensures
|
|
dst == old(RightShift(src1, src2));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(REV(dst, src))}
|
|
REV(out operand dst:word, operand src:reg)
|
|
ensures
|
|
dst == old(bswap32(src));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(MVN(dst, src))}
|
|
MVN(out operand dst:word, operand src:word)
|
|
ensures
|
|
dst == old(BitwiseNot(src));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(MOV(dst, src))}
|
|
MOV(out operand dst:word, operand src:word)
|
|
ensures
|
|
dst == old(src);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(MOV(dst, OShift(GetProbableReg(src), shift)))}
|
|
MOVShift(out operand dst:word, operand src:snd, inline shift:Shift)
|
|
ensures
|
|
dst == old(EvalShift(old(src), shift));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(LDR(dst, base, ofs))}
|
|
LDR(out operand dst:word, operand base:word, operand ofs:word)
|
|
reads
|
|
mem;
|
|
requires
|
|
ValidAddrMemStateOpaque(mem);
|
|
ValidMem(base + ofs);
|
|
ensures
|
|
dst == AddrMemContents(mem, old(base + ofs));
|
|
ensures {:refined false}
|
|
this.ok ==> ValidMem(old(base + ofs))
|
|
&& dst == MemContents(this.m, old(base + ofs));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(STR(rd, base, ofs))}
|
|
STR(operand rd:reg, operand base:word, operand ofs:word)
|
|
modifies
|
|
mem;
|
|
requires/ensures
|
|
ValidAddrMemStateOpaque(mem);
|
|
requires
|
|
ValidMem(base + ofs);
|
|
ensures
|
|
mem == AddrMemUpdate(old(mem), old(base + ofs), old(rd));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:instruction Ins(MRS(dst, src))}
|
|
MRS(out operand dst:reg, operand src:sreg)
|
|
requires
|
|
priv_of_state(this) == PL1;
|
|
ensures
|
|
dst == old(src);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:instruction Ins(MSR(dst, src))}
|
|
MSR(out operand dst:sreg, operand src:reg)
|
|
requires
|
|
priv_of_state(this) == PL1;
|
|
@dst is OSReg && @dst.sr is cpsr ==> ValidModeChange(this, src);
|
|
@dst is OSReg && @dst.sr is spsr ==> ValidPsrWord(src);
|
|
ensures
|
|
ValidMrsMsrOperand(this, @dst);
|
|
dst == old(src);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:instruction Ins(MRC(dst, src))}
|
|
MRC(out operand dst:reg, operand src:creg)
|
|
ensures
|
|
dst == old(src);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:instruction Ins(MCR(dst, src))}
|
|
MCR(out operand dst:creg, operand src:reg)
|
|
requires
|
|
// don't consider writes to SCR outside monitor mode, so we can avoid
|
|
// reasoning about the nonsense case where we drop out of secure world
|
|
@dst == OSReg(scr) ==> mode_of_state(this) == Monitor;
|
|
ensures
|
|
ValidMcrMrcOperand(this, @dst);
|
|
dst == old(src);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:frame false} {:instruction Ins(MOVS_PCLR_TO_USERMODE_AND_CONTINUE)}
|
|
MOVS_PCLR_TO_USERMODE_AND_CONTINUE()
|
|
requires/ensures
|
|
ValidState(this) && this.ok;
|
|
requires
|
|
ValidModeChange'(this, User);
|
|
spsr_of_state(this).m == User;
|
|
ensures
|
|
evalMOVSPCLRUC(old(this), this);
|
|
{
|
|
reveal va_eval;
|
|
}
|
|
|
|
procedure {:instruction Ins(CPSID_IAF(mod))} CPSID_IAF(operand mod:constop)
|
|
requires
|
|
ValidModeEncoding(mod);
|
|
ValidModeChange'(this, decode_mode(mod));
|
|
modifies
|
|
cpsr;
|
|
ensures
|
|
evalCPSID_IAF(old(this), old(mod), this);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(LDR_reloc(dst, g))}
|
|
LDRglobaladdr(out operand dst:word, inline g:symbol)
|
|
requires
|
|
ValidGlobal(g);
|
|
ensures
|
|
dst == AddressOfGlobal(g);
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(LDR_global(dst, g, base, ofs))}
|
|
LDRglobal(out operand dst:word, inline g:symbol,
|
|
operand base:word, operand ofs:word)
|
|
reads
|
|
globals;
|
|
requires
|
|
ValidGlobalStateOpaque(globals);
|
|
ValidGlobalAddr(g, base + ofs);
|
|
ensures
|
|
dst == GlobalContents(globals, g, old(base + ofs));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|
|
|
|
procedure {:bridge} {:refined} {:instruction Ins(STR_global(rd, g, base, ofs))}
|
|
STRglobal(operand rd:reg, inline g:symbol,
|
|
operand base:word, operand ofs:word)
|
|
modifies
|
|
globals;
|
|
requires
|
|
ValidGlobalStateOpaque(globals);
|
|
ValidGlobalAddr(g, base + ofs);
|
|
ensures
|
|
ValidGlobalStateOpaque(globals);
|
|
globals == GlobalUpdate(old(globals), g, old(base + ofs), old(rd));
|
|
{
|
|
reveal va_eval;
|
|
reveal ValidRegState;
|
|
this := MaybeUpdateOk(old(this), this);
|
|
}
|