зеркало из https://github.com/microsoft/Komodo.git
236 строки
9.5 KiB
Plaintext
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|