test/termination/kernel/dispatchcheck.rad 6.1 KiB raw
1
//! Native exit and fault reporting to a surviving parent.
2
use std::mem;
3
use kernel::abi;
4
use kernel::slots;
5
use kernel::backing;
6
use kernel::pages;
7
use kernel::capability;
8
use kernel::registry;
9
use kernel::loader;
10
use kernel::domains;
11
use kernel::budgets;
12
use kernel::dispatch;
13
use kernel::boot;
14
use kernel::events;
15
use kernel::sync;
16
use kernel::dispatchinput;
17
use kernel::devices;
18
use kernel::platform;
19
20
/// Bootstrap creation, allocation, and budget authority.
21
unsafe static TABLE: capability::Table = undefined;
22
/// Child domain identities retained by terminal events.
23
unsafe static CHILDREN: [abi::Ref; 6] = undefined;
24
/// Surviving event receiver and native completion checker.
25
unsafe static PARENT: abi::Ref = undefined;
26
/// Map a validated physical page.
27
fn memory(address: u64) -> *mut u8;
28
/// Current kernel package-state base.
29
fn kernelGp() -> u64;
30
/// Native entry for the completion checker.
31
fn completion() -> u64;
32
/// Signal successful completion to the machine fixture.
33
fn finish();
34
35
/// Give each child a disjoint window, followed by the surviving parent.
36
export unsafe fn setup() {
37
    let pending = try! slots::reserve(&mut domains::STORE.slots[..]);
38
    let owner = try! slots::commit(&mut domains::STORE.slots[..], pending);
39
    capability::initialize(&mut TABLE, owner);
40
    try! backing::registerDomain(&mut pages::STORE.backings, owner);
41
    let authority = try! capability::install(&mut TABLE, capability::Entry {
42
        kind: abi::Kind::Domain, object: owner, rights: abi::Rights(abi::CREATE | abi::ALLOCATE),
43
    });
44
    let source = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, (dispatchinput::INPUT.len as u64 + 4095) / 4096);
45
    let page = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, source)).object);
46
    let bytes = @sliceOf(memory(page.base), page.count * 4096);
47
    let length = try! mem::copy(&mut bytes[..], &dispatchinput::INPUT[..]);
48
    let image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE,
49
        loader::Request { authority, source, offset: 0, length: length as u64 });
50
    let parentHandle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
51
    set PARENT = (try! capability::get(&TABLE, parentHandle)).object;
52
    let parent = try! domains::get(&domains::STORE, PARENT);
53
    set domains::STORE.records[PARENT.index].state = domains::Lifecycle::Active;
54
    set domains::STORE.contexts[parent.initial.index].frame.pc = completion();
55
    set domains::STORE.contexts[parent.initial.index].frame.status = 0x1880;
56
    set domains::STORE.contexts[parent.initial.index].frame.registers[2] = domains::STORE.contexts[parent.initial.index].kernelStack.end;
57
    set domains::STORE.contexts[parent.initial.index].frame.registers[3] = kernelGp();
58
    let mut handles: [abi::Handle; 6] = undefined;
59
    let mut contexts: [abi::Ref; 6] = undefined;
60
    for i in 0..6 {
61
        let handle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
62
        let object = (try! capability::get(&TABLE, handle)).object;
63
        let mut child = try! domains::get(&domains::STORE, object);
64
        set CHILDREN[i] = object;
65
        set handles[i] = handle;
66
        set contexts[i] = child.initial;
67
        try! domains::reparent(&mut domains::STORE, &TABLE, handle, parentHandle);
68
        let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1);
69
        let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, stack, (abi::READ | abi::WRITE) as u64);
70
        let storage = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, stack)).object);
71
        let mut size = i as u64;
72
        if i == 5 {
73
            let mut installed = false;
74
            for index in 0..devices::STORE.count {
75
                if devices::STORE.regions[index].kind <> platform::Kind::Finish {
76
                    continue;
77
                }
78
                let device = try! devices::install(&devices::STORE, &mut child.memory.table, index);
79
                let args = memory(storage.base) as *mut u64;
80
                set *args = *device;
81
                set installed = true;
82
                break;
83
            }
84
            assert installed;
85
            set size = 8;
86
        }
87
        try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, handle, storage.base + 4096, storage.base, size);
88
    }
89
    let timer = try! dispatch::timer(&boot::PLATFORM, 0);
90
    let clock = dispatch::now(timer);
91
    let start = clock + 1000000;
92
    let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, start + 14000000);
93
    for i in 0..6 {
94
        let next = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + (i as u64 + 1) * 2000000, clock);
95
        let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
96
            budgets::Binding { budget: remaining, domain: handles[i], context: contexts[i] }, clock);
97
        set remaining = next;
98
    }
99
    let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
100
        budgets::Binding { budget: remaining, domain: parentHandle, context: parent.initial }, clock);
101
}
102
103
/// Check each terminal kind, status, and generation while the parent continues to run.
104
export unsafe fn verify() {
105
    let guard = sync::enter();
106
    let mut parent = try! domains::get(&domains::STORE, PARENT);
107
    let codes = [37 as u32, abi::FAULT_ABORT, 3, 0, abi::FAULT_ABORT, 51];
108
    for i in 0..6 {
109
        let event = try! events::pop(&mut parent.memory.ring) else panic "missing termination event";
110
        assert event.value == abi::id(CHILDREN[i]) and event.code == codes[i];
111
        if i == 0 or i == 3 or i == 5 {
112
            assert event.kind == events::CHILD_EXIT;
113
        }
114
        else {
115
            assert event.kind == events::FAULT;
116
        }
117
        assert domains::STORE.records[CHILDREN[i].index].state == domains::Lifecycle::Dead;
118
    }
119
    try! events::refresh(&mut domains::STORE.events, PARENT, &parent.memory.ring);
120
    assert try! events::pop(&mut parent.memory.ring) == nil;
121
    sync::leave(guard);
122
    finish();
123
}