test/smp/kernel/invariants.rad 3.4 KiB raw
1
//! Final ownership and interval checks over published kernel objects.
2
use kernel::abi;
3
use kernel::boot;
4
use kernel::slots;
5
use kernel::capability;
6
use kernel::domains;
7
use kernel::budgets;
8
use kernel::interrupts;
9
use kernel::sync;
10
11
/// Select authoritative capability storage, including the fixture's boot owner.
12
/// The bootstrap table and domain memory must outlive the metadata transaction.
13
unsafe fn table(owner: abi::Ref, bootstrap: &capability::Table) -> *unsafe capability::Table {
14
    if owner == bootstrap.owner {
15
        return bootstrap as *unsafe capability::Table;
16
    }
17
    let domain = try! domains::get(&domains::STORE, owner);
18
    assert domain.state <> domains::Lifecycle::Dead;
19
    assert domain.memory.table.owner == owner;
20
    return &domain.memory.table;
21
}
22
23
/// Check live references, exclusive execution ownership, and disjoint CPU windows.
24
/// Each budget or IRQ check uses a separate bounded metadata transaction.
25
export unsafe fn check(bootstrap: &capability::Table) {
26
    let guard = sync::enter();
27
    let mut occupied: u32 = 0;
28
    for i in 0..domains::STORE.contextSlots.len {
29
        if domains::STORE.contextSlots[i].state <> slots::State::Live {
30
            continue;
31
        }
32
        let context = domains::STORE.contexts[i];
33
        let owner = try! domains::get(&domains::STORE, context.owner);
34
        assert owner.state <> domains::Lifecycle::Dead;
35
        if let hart = context.hart {
36
            assert hart < 8 and (boot::PLATFORM.harts & (1 << hart)) <> 0;
37
            assert (occupied & (1 << hart)) == 0;
38
            set occupied |= 1 << hart;
39
        }
40
    }
41
    sync::leave(guard);
42
    for i in 0..budgets::STORE.slots.len {
43
        let guard = sync::enter();
44
        if budgets::STORE.slots[i].state == slots::State::Live {
45
            let object = abi::Ref { index: i, generation: budgets::STORE.slots[i].generation };
46
            let window = try! budgets::get(&budgets::STORE, object);
47
            assert window.start < window.end and window.hart < 8;
48
            assert (boot::PLATFORM.harts & (1 << window.hart)) <> 0;
49
            let owner = table(window.owner, bootstrap);
50
            let entry = try! capability::get(&*owner, window.handle);
51
            assert entry.kind == abi::Kind::Budget and entry.object == object;
52
            if let context = window.context {
53
                let bound = try! domains::context(&domains::STORE, window.owner, context);
54
                assert bound.owner == window.owner;
55
            }
56
            for j in i + 1..budgets::STORE.slots.len {
57
                if budgets::STORE.slots[j].state <> slots::State::Live {
58
                    continue;
59
                }
60
                let other = budgets::STORE.windows[j];
61
                if other.hart == window.hart {
62
                    assert window.end <= other.start or other.end <= window.start;
63
                }
64
            }
65
        }
66
        sync::leave(guard);
67
    }
68
    for i in 0..interrupts::STORE.count {
69
        let guard = sync::enter();
70
        if interrupts::STORE.slots[i].state == slots::State::Live {
71
            let object = abi::Ref { index: i, generation: interrupts::STORE.slots[i].generation };
72
            let irq = try! interrupts::get(&interrupts::STORE, object);
73
            let owner = table(irq.owner, bootstrap);
74
            let entry = try! capability::get(&*owner, irq.handle);
75
            assert entry.kind == abi::Kind::Interrupt and entry.object == object;
76
        }
77
        sync::leave(guard);
78
    }
79
}