test/dispatch/kernel/dispatchcheck.rad 9.0 KiB raw
1
//! Native timer preemption across user execution, idle, and machine continuations.
2
use std::mem;
3
use std::arch::rv64::shared;
4
use kernel::abi;
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::events;
16
use kernel::sync;
17
use kernel::dispatchinput;
18
19
/// Bootstrap authority used to create fixture domains and CPU windows.
20
unsafe static TABLE: capability::Table = undefined;
21
/// Domain handles used for budget binding.
22
unsafe static HANDLES: [abi::Handle; 3] = undefined;
23
/// Initial contexts for the user, machine worker, and completion check.
24
unsafe static CONTEXTS: [abi::Ref; 3] = undefined;
25
/// View a validated allocated source page.
26
fn memory(address: u64) -> *mut u8;
27
/// Current kernel package-state base.
28
fn kernelGp() -> u64;
29
/// Native entry for retained M-mode work.
30
fn worker() -> u64;
31
/// Native entry for the final assertion callback.
32
fn completion() -> u64;
33
/// Complete the machine fixture with a passing status.
34
fn finish();
35
/// Complete the fixture with a distinct failed invariant code.
36
fn failed(code: u64);
37
38
/// Prepare real private domains before enabling dispatch on hart zero.
39
export unsafe fn setup() {
40
    let pending = try! slots::reserve(&mut domains::STORE.slots[..]);
41
    let owner = try! slots::commit(&mut domains::STORE.slots[..], pending);
42
    capability::initialize(&mut TABLE, owner);
43
    try! backing::registerDomain(&mut pages::STORE.backings, owner);
44
    let authority = try! capability::install(&mut TABLE, capability::Entry {
45
        kind: abi::Kind::Domain, object: owner, rights: abi::Rights(abi::CREATE | abi::ALLOCATE),
46
    });
47
    let source = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, (dispatchinput::INPUT.len as u64 + 4095) / 4096);
48
    let sourceEntry = try! capability::get(&TABLE, source);
49
    let page = try! pages::get(&pages::STORE, sourceEntry.object);
50
    let bytes = @sliceOf(memory(page.base), page.count * 4096);
51
    let length = try! mem::copy(&mut bytes[..], &dispatchinput::INPUT[..]);
52
    let image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE,
53
        loader::Request { authority, source, offset: 0, length: length as u64 });
54
    for i in 0..3 {
55
        set HANDLES[i] = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
56
        let cap = try! capability::get(&TABLE, HANDLES[i]);
57
        let child = try! domains::get(&domains::STORE, cap.object);
58
        set CONTEXTS[i] = child.initial;
59
        if i > 0 {
60
            set domains::STORE.records[cap.object.index].state = domains::Lifecycle::Active;
61
            set domains::STORE.contexts[child.initial.index].frame.status = 0x1880;
62
            set domains::STORE.contexts[child.initial.index].frame.registers[2] = domains::STORE.contexts[child.initial.index].kernelStack.end;
63
            set domains::STORE.contexts[child.initial.index].frame.registers[3] = kernelGp();
64
        }
65
    }
66
    let cap = try! capability::get(&TABLE, HANDLES[0]);
67
    let mut user = try! domains::get(&domains::STORE, cap.object);
68
    let selfAuthority = try! capability::install(&mut user.memory.table, capability::Entry {
69
        kind: abi::Kind::Domain, object: cap.object, rights: abi::Rights(abi::CREATE | abi::ALLOCATE | abi::EXECUTE | abi::WAKE | abi::DESTROY),
70
    });
71
    let root = user.image;
72
    let executable = try! registry::install(&registry::STORE, &mut user.memory.table, root);
73
    let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1);
74
    let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut user.memory.table, stack, (abi::READ | abi::WRITE) as u64);
75
    let stackCap = try! capability::get(&TABLE, stack);
76
    let stackPage = try! pages::get(&pages::STORE, stackCap.object);
77
    let parent = try! capability::install(&mut user.memory.table, capability::Entry {
78
        kind: abi::Kind::Domain, object: domains::STORE.contexts[CONTEXTS[2].index].owner, rights: abi::Rights(abi::WAKE),
79
    });
80
    let args = @sliceOf(memory(stackPage.base), 40);
81
    let words = [*granted, *executable, *selfAuthority];
82
    for word in 0..3 {
83
        for byte in 0..8 {
84
            set args[word * 8 + byte] = (words[word] >> (byte as u64 * 8)) as u8;
85
        }
86
    }
87
    for byte in 0..8 {
88
        set args[32 + byte] = (*parent >> (byte as u64 * 8)) as u8;
89
    }
90
    try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, HANDLES[0], stackPage.base + 4096, stackPage.base, 40);
91
    let imageRef = try! registry::image(&registry::STORE, &TABLE, image, abi::Rights(abi::EXECUTE));
92
    let target = try! registry::exported(&registry::STORE, imageRef, &"spin::count"[..]);
93
    let case shared::Target::Data(data) = target else panic "counter";
94
    let timer = try! dispatch::timer(&boot::PLATFORM, 0);
95
    let clock = dispatch::now(timer);
96
    let start = clock + 1000000;
97
    let span: u64 = 8000000;
98
    set domains::STORE.contexts[CONTEXTS[1].index].frame.pc = worker();
99
    set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[10] = user.graph.table[data.slot] + data.offset as u64;
100
    set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[11] = timer.clock;
101
    set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[12] = start + 3 * span;
102
    set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[13] = start + 4 * span;
103
    set domains::STORE.contexts[CONTEXTS[2].index].frame.pc = completion();
104
    let mut windows: [abi::Handle; 6] = undefined;
105
    let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, start + 6 * span);
106
    for i in 0..6 {
107
        set windows[i] = remaining;
108
        if i < 5 {
109
            set remaining = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + (i as u64 + 1) * span, clock);
110
        }
111
    }
112
    let owners = &[0 as u32, 0, 1, 0, 1, 2];
113
    for i in 0..6 {
114
        if i == 1 {
115
            continue;
116
        }
117
        let owner = owners[i];
118
        let handle = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
119
            budgets::Binding { budget: windows[i], domain: HANDLES[owner], context: CONTEXTS[owner] }, clock);
120
        if i == 3 {
121
            for byte in 0..8 {
122
                set args[24 + byte] = (*handle >> (byte as u64 * 8)) as u8;
123
            }
124
        }
125
    }
126
}
127
128
/// Check state captured by production timer handling after both resumptions.
129
export unsafe fn verify() {
130
    let user = domains::STORE.contexts[CONTEXTS[0].index].frame;
131
    let machine = domains::STORE.contexts[CONTEXTS[1].index].frame;
132
    assert (user.status & 0x1800) == 0 and (machine.status & 0x1800) == 0x1800;
133
    assert machine.registers[8] > 0 and machine.registers[9] == 1 and machine.registers[18] > 0;
134
    let mut domain = try! domains::get(&domains::STORE, domains::STORE.contexts[CONTEXTS[0].index].owner);
135
    let target = try! registry::exported(&registry::STORE, domain.image, &"spin::extraCount"[..]);
136
    let case shared::Target::Data(data) = target else panic "extra counter";
137
    let bytes = @sliceOf(memory(domain.graph.table[data.slot] + data.offset as u64), 8);
138
    let mut progress: u64 = 0;
139
    for byte in 0..8 {
140
        set progress |= bytes[byte] as u64 << (byte as u64 * 8);
141
    }
142
    if progress == 0 {
143
        failed(6);
144
    }
145
    let checked = try! registry::exported(&registry::STORE, domain.image, &"spin::destroyed"[..]);
146
    let case shared::Target::Data(flag) = checked else panic "destruction flag";
147
    if *memory(domain.graph.table[flag.slot] + flag.offset as u64) <> 1 {
148
        failed(7);
149
    }
150
    let child = try! registry::exported(&registry::STORE, domain.image, &"spin::childId"[..]);
151
    let case shared::Target::Data(identity) = child else panic "child identity";
152
    let idBytes = @sliceOf(memory(domain.graph.table[identity.slot] + identity.offset as u64), 8);
153
    let mut childId: u64 = 0;
154
    for byte in 0..8 {
155
        set childId |= idBytes[byte] as u64 << (byte as u64 * 8);
156
    }
157
    let owner = domains::STORE.contexts[CONTEXTS[2].index].owner;
158
    let guard = sync::enter();
159
    let mut checker = try! domains::get(&domains::STORE, owner);
160
    assert try! events::flush(&mut domains::STORE.events, owner, &mut checker.memory.ring) == 0;
161
    assert not try! events::acknowledged(&domains::STORE.events, abi::reference(childId));
162
    let exited = try! events::pop(&mut checker.memory.ring) else panic "child exit";
163
    assert exited.kind == events::CHILD_EXIT and exited.code == 0 and exited.value == childId;
164
    try! events::refresh(&mut domains::STORE.events, owner, &checker.memory.ring);
165
    assert try! events::acknowledged(&domains::STORE.events, abi::reference(childId));
166
    sync::leave(guard);
167
    let wake = try! events::pop(&mut domain.memory.ring) else panic "wake token";
168
    assert wake.kind == events::WAKEUP and wake.code == 123;
169
    let timeout = try! events::pop(&mut domain.memory.ring) else panic "timeout token";
170
    assert timeout.kind == events::TIMEOUT and timeout.code == 77 and timeout.value == 0;
171
    assert try! events::pop(&mut domain.memory.ring) == nil;
172
    finish();
173
}