test/scheduling/kernel/dispatchcheck.rad 2.7 KiB raw
1
//! Observe user-space bootstrap and scheduling at the trap boundary.
2
use kernel::abi;
3
use std::lang::il;
4
use kernel::trap;
5
use kernel::dispatch;
6
use kernel::domains;
7
use kernel::budgets;
8
use kernel::events;
9
use kernel::sync;
10
11
/// Root has requested normal termination.
12
static ROOT_EXITED: bool = false;
13
/// Workers that returned after root released its authority.
14
static WORKERS: u32 = 0;
15
/// Write one byte to the test UART.
16
fn put(value: u8);
17
/// Most recent user operation for fault diagnosis.
18
static LAST_CALL: u64 = 0;
19
20
/// Print a complete hexadecimal diagnostic word.
21
fn number(value: u64) {
22
    let digits = "0123456789abcdef";
23
    for i in 0..16 {
24
        put(digits[((value >> ((15 - i) as u64 * 4)) & 15) as u32]);
25
    }
26
    put(10);
27
}
28
29
/// Check terminal calls without changing user-domain resources or execution.
30
export unsafe fn observe(frame: &trap::Frame) {
31
    if not trap::fromUser(frame) {
32
        return;
33
    }
34
    let cause = trap::classify(frame.cause);
35
    if cause == trap::Cause::Timer or cause == trap::Cause::Software or cause == trap::Cause::External {
36
        return;
37
    }
38
    if cause <> trap::Cause::UserCall {
39
        number(frame.cause); number(frame.pc); number(LAST_CALL); number(WORKERS as u64);
40
        assert false;
41
    }
42
    set LAST_CALL = frame.registers[17];
43
    assert frame.registers[17] <> abi::Operation::Abort as u64;
44
    let shutdown = frame.registers[17] == il::DEVICE_ACCESS as u64 and frame.registers[12] == 0x104;
45
    if frame.registers[17] <> abi::Operation::Exit as u64 and not shutdown {
46
        return;
47
    }
48
    let current = dispatch::current();
49
    let context = abi::reference(current.context);
50
    let guard = sync::enter();
51
    let owner = domains::STORE.contexts[context.index].owner;
52
    if owner.index == 0 {
53
        assert frame.registers[10] == 0;
54
        set ROOT_EXITED = true;
55
    } else if owner.index == 1 {
56
        assert ROOT_EXITED and WORKERS == 4 and shutdown and frame.registers[13] == 0x5555;
57
        let scheduler = try! domains::get(&domains::STORE, owner);
58
        assert scheduler.parent == nil;
59
        let ring = &scheduler.memory.ring;
60
        assert ring.tail - ring.head == 5;
61
        assert ring.data[ring.head & ring.mask].kind == events::CHILD_EXIT;
62
        assert ring.data[ring.head & ring.mask].code == 0;
63
        for i in 1..5 {
64
            let event = ring.data[(ring.head + i) & ring.mask];
65
            assert event.kind == events::CHILD_EXIT and event.code == 7;
66
        }
67
        let future = try! budgets::query(&budgets::STORE, &scheduler.memory.table, abi::Handle(current.budget));
68
        assert future.end > dispatch::clock();
69
        sync::leave(guard);
70
        return;
71
    } else {
72
        assert ROOT_EXITED and frame.registers[10] == 7;
73
        set WORKERS += 1;
74
    }
75
    sync::leave(guard);
76
}