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