Komodo/verified/remove.sdfy

236 строки
9.5 KiB
Plaintext

include {:verbatim} "kom_common.i.dfy"
include {:verbatim} "pagedb.i.dfy"
include {:verbatim} "smcapi.i.dfy"
include "ARMdecls.sdfy"
include "kom_utils.sdfy"
procedure kom_smc_remove_non_addr_success(
operand page:reg,
operand pagedb_base:reg,
operand page_type:reg,
operand as_page_va:reg,
ghost pagedb_in: PageDb)
returns (ghost pagedb: PageDb)
requires/ensures
SaneState(this);
requires
@page == OReg(R1) && @pagedb_base == OReg(R12) && @page_type == OReg(R5);
@as_page_va == OReg(R6);
validPageDb(pagedb_in);
pageDbCorresponds(this.m, pagedb_in);
specErr(smc_remove(pagedb_in,page)) == KOM_ERR_SUCCESS;
pagedb_in[page] is PageDbEntryTyped && !(pagedb_in[page].entry is Addrspace);
pagedb_base == AddressOfGlobal(PageDb());
page_type == G_PAGEDB_ENTRY(page) + PAGEDB_ENTRY_TYPE;
as_page_va == page_monvaddr(pagedb_in[page].addrspace);
modifies
globals; mem; r7;
ensures
SmcProcedureInvariant(old(this), this);
pagedb == specPageDb(smc_remove_premium(pagedb_in, old(page)));
pageDbCorresponds(this.m, pagedb);
{
reveal smc_remove_premium;
ghost var specResult := smc_remove_premium(pagedb_in, page);
ghost var specE := specErr(specResult);
ghost var specD := specPageDb(specResult);
ghost var as_page := pagedb_in[page].addrspace;
pagedb := pagedb_in;
forall :: pagedb[as_page] is PageDbEntryTyped &&
pagedb[as_page].entry is Addrspace {
reveal_validPageDb();
}
r7 := const(KOM_PAGE_FREE);
assert page_type == G_PAGEDB_ENTRY(page) + PAGEDB_ENTRY_TYPE;
STRglobal(r7, PageDb(), pagedb_base, page_type);
extractPageDbToAbstract(this.m, page);
assert extractPageDbEntry(this.m, page)[
BytesToWords(PAGEDB_ENTRY_TYPE)] == KOM_PAGE_FREE;
LDR(r7, as_page_va, const(ADDRSPACE_REF));
forall :: r7 == pagedb[as_page].entry.refcount {
reveal_validPageDb();
reveal_pageContentsCorresponds();
reveal_pageDbAddrspaceCorresponds();
}
SUB(r7, r7, 1);
assert r7 == pagedb[as_page].entry.refcount - 1;
STR(r7, as_page_va, const(ADDRSPACE_REF));
pagedb := specD;
assert pageDbCorresponds(this.m, pagedb) by {
reveal_validPageDb();
forall :: pageDbCorrespondsOnly(this.m, specD, page)
{
reveal_pageDbEntryCorresponds();
reveal_pageContentsCorresponds();
}
forall :: pageDbCorrespondsOnly(this.m, specD, as_page)
{
reveal_pageDbEntryCorresponds();
assert pagedb[as_page].addrspace ==
pagedb_in[as_page].addrspace;
assert extractPageDbEntry(this.m, as_page) ==
extractPageDbEntry(old(this.m), as_page);
reveal_pageContentsCorresponds();
reveal_pageDbAddrspaceCorresponds();
ghost var e := specD[as_page].entry;
ghost var base := page_monvaddr(as_page);
ghost var page := extractPage(this.m, as_page);
assert base == as_page_va;
assert page[base + ADDRSPACE_L1PT] ==
page_monvaddr(e.l1ptnr);
assert page[base + ADDRSPACE_L1PT_PHYS] ==
page_paddr(e.l1ptnr);
assert page[base + ADDRSPACE_REF] == e.refcount;
assert page[base + ADDRSPACE_STATE] ==
pageDbAddrspaceStateVal(e.state);
}
forall p :| validPageNr(p) && p != as_page && p != page ::
pageDbCorrespondsOnly(this.m, specD, p)
{
reveal_pageDbEntryCorresponds();
forall p :| validPageNr(p) && p != as_page && p != page ::
(extractPage(this.m, p) ==
extractPage(old(this.m), p)) {}
reveal_pageContentsCorresponds();
forall p :| validPageNr(p) && p != as_page && p != page ::
(extractPageDbEntry(this.m, p) ==
extractPageDbEntry(old(this.m), p)) {}
forall p :| validPageNr(p) && p != as_page && p != page ::
pagedb[p] == pagedb_in[p] {}
assert pageDbCorrespondsOnly(old(this.m), pagedb, p);
}
}
}
procedure kom_smc_remove(
operand page:reg,
operand pagedb_base:reg,
out operand err:reg,
ghost pagedb_in: PageDb)
returns (ghost pagedb: PageDb)
requires/ensures
SaneState(this);
requires
@page == OReg(R1) && @err == OReg(R0);
@pagedb_base == OReg(R12);
pagedb_base == AddressOfGlobal(PageDb());
validPageDb(pagedb_in);
pageDbCorresponds(this.m, pagedb_in);
modifies
globals; mem; r5; r6; r7; r8;
ensures
SmcProcedureInvariant(old(this), this);
tuple(pagedb,err) == smc_remove_premium(pagedb_in, old(page));
pageDbCorresponds(this.m, pagedb);
{
reveal smc_remove_premium;
ghost var specResult := smc_remove_premium(pagedb_in, page);
ghost var specE := specErr(specResult);
ghost var specD := specPageDb(specResult);
pagedb := pagedb_in;
if ( page >= const(KOM_SECURE_NPAGES) ){
err := const(KOM_ERR_INVALID_PAGENO);
assert err == specE;
assert pagedb == specD;
} else {
assert validPageNr(page);
load_page_type(page, pagedb_base, r5, r6, pagedb);
if (r6 == const(KOM_PAGE_FREE)) {
assert pagedb[page] is PageDbEntryFree;
err := const(KOM_ERR_SUCCESS);
assert err == specE;
} else {
assert pagedb[page] is PageDbEntryTyped;
if( r6 == const(KOM_PAGE_ADDRSPACE) ){
assert pagedb[page].entry is Addrspace;
page_monvaddr_impl(r8,page,r7);
assert r8 == page_monvaddr(page);
LDR(r7,r8,const(ADDRSPACE_REF));
forall :: r7 == pagedb[page].entry.refcount {
reveal_validPageDb();
reveal_pageContentsCorresponds();
reveal_pageDbAddrspaceCorresponds();
}
if (r7 != 0) {
assert pagedb[page].entry.refcount != 0;
err := const(KOM_ERR_PAGEINUSE);
assert err == specE;
} else {
assert pagedb[page].entry.refcount == 0;
assert r7 == KOM_PAGE_FREE == 0;
assert r5 == G_PAGEDB_ENTRY(page) + PAGEDB_ENTRY_TYPE;
STRglobal(r7, PageDb(), pagedb_base, r5);
err := const(KOM_ERR_SUCCESS);
assert err == specE;
pagedb := specD;
assert pageDbCorresponds(this.m, pagedb) by {
reveal_validPageDb();
reveal_pageDbEntryCorresponds();
reveal_pageContentsCorresponds();
assert specD[page] is PageDbEntryFree;
extractPageDbToAbstract(this.m, page);
assert pageDbEntryCorresponds(specD[page],
extractPageDbEntry(this.m, page));
assert pageDbCorrespondsOnly(this.m, specD, page);
forall :: pageDbCorrespondsExcluding(this.m, specD, page)
{
reveal_validPageDb();
reveal_pageContentsCorresponds();
reveal_pageDbAddrspaceCorresponds();
ghost var d' := specPageDb(specResult);
assert pageDbCorrespondsExcluding(old(this).m, pagedb, page);
forall :: pageDbCorrespondsExcluding(this.m, pagedb, page)
{
forall p :| validPageNr(p) && p != page ::
extractPage(this.m, p) == extractPage(old(this).m, p) {}
}
forall p :| validPageNr(p) && p != page :: pagedb[p] == d'[p] {}
}
}
}
} else {
assert pagedb[page] is PageDbEntryTyped;
ADD(r6, r5, const(PAGEDB_ENTRY_ADDRSPACE));
assert r6 == G_PAGEDB_ENTRY(page) + PAGEDB_ENTRY_ADDRSPACE;
LDRglobal(r6, PageDb(), pagedb_base, r6);
ghost var as_page := pagedb[page].addrspace;
forall :: r6 == page_monvaddr(as_page) {
reveal_pageDbEntryCorresponds();
extractPageDbToAbstract(this.m, page);
}
forall :: pagedb[as_page] is PageDbEntryTyped &&
pagedb[as_page].entry is Addrspace {
reveal_validPageDb();
}
//page_monvaddr_impl(r7,r6,r8);
LDR(r8,r6,const(ADDRSPACE_STATE));
forall :: r8 == pageDbAddrspaceStateVal(pagedb[as_page].entry.state)
{
reveal_pageContentsCorresponds();
reveal_pageDbAddrspaceCorresponds();
}
if ( r8 != const(KOM_ADDRSPACE_STOPPED) ) {
err := const(KOM_ERR_NOT_STOPPED);
assert err == specE;
} else {
assert specE == KOM_ERR_SUCCESS;
assert r5 == G_PAGEDB_ENTRY(page) + PAGEDB_ENTRY_TYPE;
assert r6 == page_monvaddr(as_page);
pagedb := kom_smc_remove_non_addr_success(page,pagedb_base,r5,r6,pagedb);
err := const(KOM_ERR_SUCCESS);
}
}
}
}
}