test/runtime/kernel/dispatchcheck.rad 11.1 KiB raw
1
//! Runtime compiler ownership across scheduled windows and domain destruction.
2
use std::mem;
3
use kernel::abi;
4
use kernel::frames;
5
use kernel::slots;
6
use kernel::backing;
7
use kernel::pages;
8
use kernel::capability;
9
use kernel::registry;
10
use kernel::loader;
11
use kernel::domains;
12
use kernel::budgets;
13
use kernel::dispatch;
14
use kernel::boot;
15
use kernel::sync;
16
use kernel::calls;
17
use kernel::lifecycle;
18
use kernel::remote;
19
use kernel::dispatchinput;
20
21
/// Bootstrap resource capabilities.
22
unsafe static TABLE: capability::Table = undefined;
23
/// First loader, retry loader, witness, and controller domain handles.
24
unsafe static HANDLES: [abi::Handle; 4] = undefined;
25
/// Generation-bearing domain identities for each actor.
26
unsafe static ACTORS: [abi::Ref; 4] = undefined;
27
/// Initial context identities for each actor.
28
unsafe static CONTEXTS: [abi::Ref; 4] = undefined;
29
/// Controller capability for the first loader.
30
unsafe static VICTIM: abi::Handle = undefined;
31
/// Controller capability for the binary input page.
32
unsafe static SOURCE: abi::Handle = undefined;
33
/// Shared user progress and published package identity.
34
unsafe static PROGRESS: *mut u64 = undefined;
35
/// Start of the controller's final execution window.
36
static FINAL: u64 = 0;
37
/// Write one diagnostic byte to the fixture UART.
38
fn put(byte: u8);
39
/// Write a fixed-width hexadecimal diagnostic value.
40
fn number(value: u64) {
41
    let digits = "0123456789abcdef";
42
    for i in 0..16 { put(digits[((value >> ((15 - i) as u64 * 4)) & 15) as u32]); }
43
}
44
45
/// Map a validated physical page.
46
fn memory(address: u64) -> *mut u8;
47
/// Current kernel package-state base.
48
fn kernelGp() -> u64;
49
/// Native controller entry address.
50
fn completion() -> u64;
51
/// Execute published code with one private package-state table.
52
fn invoke(address: u64, table: u64) -> i64;
53
/// Signal native fixture completion.
54
fn finish();
55
56
/// Copy trusted package bytes into a bootstrap-owned page allocation.
57
unsafe fn input(authority: abi::Handle, bytes: &[u8]) -> abi::Handle {
58
    let handle = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, (bytes.len as u64 + 4095) / 4096);
59
    let page = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, handle)).object);
60
    let copied = try! mem::copy(@sliceOf(memory(page.base), page.count * 4096), bytes);
61
    assert copied == bytes.len;
62
    return handle;
63
}
64
65
/// Install user actors and disjoint windows that interrupt two compiler calls.
66
export unsafe fn setup() {
67
    let pending = try! slots::reserve(&mut domains::STORE.slots[..]);
68
    let owner = try! slots::commit(&mut domains::STORE.slots[..], pending);
69
    capability::initialize(&mut TABLE, owner);
70
    try! backing::registerDomain(&mut pages::STORE.backings, owner);
71
    let authority = try! capability::install(&mut TABLE, capability::Entry {
72
        kind: abi::Kind::Domain, object: owner, rights: abi::Rights(abi::CREATE | abi::ALLOCATE),
73
    });
74
    let source = input(authority, &dispatchinput::INPUT[..]);
75
    let image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE,
76
        loader::Request { authority, source, offset: 0, length: dispatchinput::INPUT.len as u64 });
77
    let payload = input(authority, &dispatchinput::PAYLOAD[..]);
78
    let progress = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1);
79
    let shared = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, progress)).object);
80
    set PROGRESS = memory(shared.base) as *mut u64;
81
    for i in 0..4 {
82
        let handle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
83
        let object = (try! capability::get(&TABLE, handle)).object;
84
        let mut child = try! domains::get(&domains::STORE, object);
85
        let mut rights = abi::ALLOCATE;
86
        if i == 3 { set rights |= abi::CREATE; }
87
        let self = try! capability::install(&mut child.memory.table, capability::Entry {
88
            kind: abi::Kind::Domain, object, rights: abi::Rights(rights),
89
        });
90
        set HANDLES[i] = handle; set ACTORS[i] = object; set CONTEXTS[i] = child.initial;
91
        let readable = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, payload, abi::READ as u64);
92
        let writable = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, progress, (abi::READ | abi::WRITE) as u64);
93
        if i == 3 {
94
            set SOURCE = readable;
95
            set VICTIM = try! capability::install(&mut child.memory.table, capability::Entry {
96
                kind: abi::Kind::Domain, object: ACTORS[0], rights: abi::Rights(abi::DESTROY),
97
            });
98
            set domains::STORE.records[object.index].state = domains::Lifecycle::Active;
99
            let frame = &mut domains::STORE.contexts[child.initial.index].frame;
100
            set frame.pc = completion(); set frame.status = 0x1880;
101
            set frame.registers[2] = domains::STORE.contexts[child.initial.index].kernelStack.end;
102
            set frame.registers[3] = kernelGp();
103
            continue;
104
        }
105
        let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1);
106
        let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, stack, (abi::READ | abi::WRITE) as u64);
107
        let storage = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, stack)).object);
108
        let args = @sliceOf(memory(storage.base) as *mut u64, 3);
109
        set args[0] = *readable; set args[1] = dispatchinput::PAYLOAD.len as u64; set args[2] = shared.base;
110
        try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, handle, storage.base + 4096, storage.base, i as u64);
111
    }
112
    for byte in "runtime actors ready\n" { put(byte); }
113
    let now = dispatch::clock();
114
    let start = now + 1000000;
115
    set FINAL = start + 300000000;
116
    let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, FINAL + 10000000);
117
    let actors = [0 as u32, 3, 1, 2, 1];
118
    let ends = [10000000 as u64, 50000000, 60000000, 62000000, 300000000];
119
    for i in 0..5 {
120
        let next = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + ends[i], now);
121
        let actor = actors[i];
122
        let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
123
            budgets::Binding { budget: remaining, domain: HANDLES[actor], context: CONTEXTS[actor] }, now);
124
        set remaining = next;
125
    }
126
    let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
127
        budgets::Binding { budget: remaining, domain: HANDLES[3], context: CONTEXTS[3] }, now);
128
}
129
130
/// Verify cancellation, competing admission, progress, and resident code reuse.
131
export unsafe fn verify() {
132
    for byte in "runtime admission metadata instructions: " { put(byte); }
133
    number(sync::maximum()); put(10);
134
    let admissionWait = sync::maximumWait();
135
    assert admissionWait > 0;
136
    for byte in "runtime admission acquisition instructions: " { put(byte); }
137
    number(admissionWait); put(10);
138
    let progress = @sliceOf(PROGRESS, 4);
139
    let guard = sync::enter();
140
    let first = CONTEXTS[0];
141
    for byte in "runtime first progress and owner: " { put(byte); }
142
    number(progress[0]); put(32); number(abi::id(loader::STATE.owner)); put(10);
143
    assert progress[0] == 1 and loader::STATE.busy and loader::STATE.owner == ACTORS[0];
144
    assert domains::STORE.contexts[first.index].reservation;
145
    assert (domains::STORE.contexts[first.index].frame.status & 0x1800) == 0x1800;
146
    let allocation = lifecycle::CALLS.records[first.index].allocation;
147
    let mut loading: lifecycle::Loading = undefined;
148
    match allocation {
149
        case lifecycle::Allocation::Load(value) => { set loading = value; },
150
        else => panic "loader reservation required",
151
    }
152
    let output = loading.output else panic "compilation output required";
153
    sync::leave(guard);
154
    let mut busy = false;
155
    try calls::synchronized(ACTORS[3], 51, &[0, *SOURCE, 0, dispatchinput::PAYLOAD.len as u64], dispatch::clock()) catch error {
156
        assert error == abi::Error::Busy; set busy = true;
157
    };
158
    assert busy;
159
    for byte in "runtime competing load rejected\n" { put(byte); }
160
    let destroyed = try! calls::synchronized(ACTORS[3], 22, &[*VICTIM, 0, 0, 0], dispatch::clock());
161
    assert destroyed == 0;
162
    let checking = sync::enter();
163
    let request = try! dispatch::request(0, remote::Action::Reschedule);
164
    sync::leave(checking);
165
    let result = try! dispatch::awaitRequest(0, request);
166
    assert result == 0;
167
    let cancelled = sync::enter();
168
    assert not loader::STATE.busy;
169
    assert (lifecycle::CALLS.active[first.index / 32] & (1 << (first.index % 32))) == 0;
170
    assert registry::STORE.slots[output.object.index].state == slots::State::Free;
171
    sync::leave(cancelled);
172
    let mut reclaimed = false;
173
    for attempt in 0..10000 {
174
        let guard = sync::enter();
175
        set reclaimed = pages::STORE.backings.pool.retiredCount == 0;
176
        if reclaimed { sync::leave(guard); break; }
177
        let request = try! dispatch::request(0, remote::Action::Reschedule);
178
        sync::leave(guard);
179
        let result = try! dispatch::awaitRequest(0, request);
180
        assert result == 0;
181
    }
182
    assert reclaimed;
183
    for run in [loading.input.frames, output.code, output.metadata] {
184
        let mut offset: u32 = 0;
185
        while offset < run.count {
186
            let mut count = run.count - offset;
187
            if count > 256 { set count = 256; }
188
            let recovered = sync::enter();
189
            for i in run.first + offset..run.first + offset + count { assert frames::available(&pages::STORE.backings.pool, i); }
190
            sync::leave(recovered);
191
            set offset += count;
192
        }
193
    }
194
    for byte in "runtime cancellation passed\n" { put(byte); }
195
    while dispatch::clock() < FINAL {}
196
    let complete = sync::enter();
197
    for byte in "runtime final progress: " { put(byte); }
198
    for i in 0..4 { number(progress[i]); put(32); }
199
    put(10);
200
    assert progress[0] == 1 and progress[1] == 2 and progress[2] == 1;
201
    assert not loader::STATE.busy;
202
    let package = try! registry::get(&registry::STORE, abi::reference(progress[3]));
203
    let entry = package.entry else panic "published entry required";
204
    let mut controller = try! domains::get(&domains::STORE, ACTORS[3]);
205
    let image = try! registry::install(&registry::STORE, &mut controller.memory.table, abi::reference(progress[3]));
206
    sync::leave(complete);
207
    let handle = abi::Handle(try! calls::synchronized(ACTORS[3], 20, &[0, *image, 0, 0], dispatch::clock()));
208
    let created = sync::enter();
209
    let object = (try! capability::get(&controller.memory.table, handle)).object;
210
    let domain = try! domains::get(&domains::STORE, object);
211
    sync::leave(created);
212
    assert invoke(entry, domain.graph.table.ptr as u64) == 43;
213
    assert invoke(entry, domain.graph.table.ptr as u64) == 85;
214
    for byte in "runtime retry published executable code\n" { put(byte); }
215
    let maximum = sync::maximum();
216
    for byte in "runtime metadata instructions: " { put(byte); }
217
    number(maximum); put(10);
218
    assert maximum > 0 and maximum < 1000000;
219
    let waiting = sync::maximumWait();
220
    assert waiting > 0;
221
    for byte in "runtime acquisition instructions: " { put(byte); }
222
    number(waiting); put(10);
223
    finish();
224
}