test/cycles/kernel/dispatchcheck.rad 10.7 KiB raw
1
//! Concurrent private package graphs and complete worker resource recovery.
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::remote;
17
use kernel::events;
18
use kernel::devices;
19
use kernel::platform;
20
use kernel::invariants;
21
use kernel::dispatchinput;
22
23
/// Bootstrap resource capabilities.
24
unsafe static TABLE: capability::Table = undefined;
25
/// Fixture publication barrier.
26
static READY: u64 = 0;
27
/// Surviving event consumer.
28
unsafe static PARENT: abi::Ref = undefined;
29
/// Controller identities indexed by hart.
30
unsafe static CHILDREN: [abi::Ref; 8] = undefined;
31
/// Bootstrap-owned argument page addresses indexed by hart.
32
static ARGUMENTS: [u64; 8] = [0; 8];
33
/// Free frames before controller creation.
34
static FREE: u32 = 0;
35
/// Reusable page, backing, domain, and context slots before controller creation.
36
static SLOTS: [u32; 4] = [0; 4];
37
/// Validated physical page mapping.
38
fn memory(address: u64) -> *mut u8;
39
/// Current kernel package-state table.
40
fn kernelGp() -> u64;
41
/// Native checker entry.
42
fn completion() -> u64;
43
/// Write one diagnostic byte.
44
fn put(byte: u8);
45
/// Finish the native fixture.
46
fn finish();
47
48
/// Count reusable frames in short metadata sections.
49
unsafe fn freeFrames() -> u32 {
50
    let mut count: u32 = 0;
51
    let mut first: u32 = 0;
52
    while first < pages::STORE.backings.pool.count {
53
        let mut end = first + 128;
54
        if end > pages::STORE.backings.pool.count { set end = pages::STORE.backings.pool.count; }
55
        let guard = sync::enter();
56
        for i in first..end { if frames::available(&pages::STORE.backings.pool, i) { set count += 1; } }
57
        sync::leave(guard);
58
        set first = end;
59
    }
60
    return count;
61
}
62
63
/// Count reusable object slots after all allocation transactions have stopped.
64
fn freeSlots(entries: &[slots::Slot]) -> u32 {
65
    let mut count: u32 = 0;
66
    let mut first: u32 = 0;
67
    while first < entries.len {
68
        let mut end = first + 128;
69
        if end > entries.len { set end = entries.len; }
70
        let guard = sync::enter();
71
        for i in first..end {
72
            assert entries[i].state <> slots::State::Reserved;
73
            if entries[i].state == slots::State::Free { set count += 1; }
74
        }
75
        sync::leave(guard);
76
        set first = end;
77
    }
78
    return count;
79
}
80
81
/// Read object capacity at the quiescent boundaries of the workload.
82
unsafe fn capacity() -> [u32; 4] {
83
    return [freeSlots(&pages::STORE.slots[..]), freeSlots(&pages::STORE.backings.slots[..]),
84
        freeSlots(&domains::STORE.slots[..]), freeSlots(&domains::STORE.contextSlots[..])];
85
}
86
87
/// Copy one trusted package into bootstrap-owned memory.
88
unsafe fn input(authority: abi::Handle, bytes: &[u8]) -> abi::Handle {
89
    let handle = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, (bytes.len as u64 + 4095) / 4096);
90
    let page = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, handle)).object);
91
    assert try! mem::copy(@sliceOf(memory(page.base), page.count * 4096), bytes) == bytes.len;
92
    return handle;
93
}
94
95
/// Publish fixture state before any hart enters dispatch.
96
export unsafe fn start(last: bool) {
97
    if last { setup(); sync::storeRelease(&mut READY, 1); }
98
    while sync::loadAcquire(&READY) == 0 {}
99
}
100
101
/// Prepare one controller per hart and a later surviving checker.
102
unsafe fn setup() {
103
    let pending = try! slots::reserve(&mut domains::STORE.slots[..]);
104
    let owner = try! slots::commit(&mut domains::STORE.slots[..], pending);
105
    capability::initialize(&mut TABLE, owner);
106
    try! backing::registerDomain(&mut pages::STORE.backings, owner);
107
    let authority = try! capability::install(&mut TABLE, capability::Entry {
108
        kind: abi::Kind::Domain, object: owner, rights: abi::Rights(abi::CREATE | abi::ALLOCATE),
109
    });
110
    let mut image = abi::Handle(0);
111
    for bytes in [&dispatchinput::support[..], &dispatchinput::spin[..]] {
112
        let source = input(authority, &bytes[..]);
113
        set image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE,
114
            loader::Request { authority, source, offset: 0, length: bytes.len as u64 });
115
    }
116
    let source = input(authority, &dispatchinput::job[..]);
117
    let parentHandle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
118
    set PARENT = (try! capability::get(&TABLE, parentHandle)).object;
119
    let parent = try! domains::get(&domains::STORE, PARENT);
120
    set domains::STORE.records[PARENT.index].state = domains::Lifecycle::Active;
121
    let frame = &mut domains::STORE.contexts[parent.initial.index].frame;
122
    set frame.pc = completion(); set frame.status = 0x1880;
123
    set frame.registers[2] = domains::STORE.contexts[parent.initial.index].kernelStack.end;
124
    set frame.registers[3] = kernelGp();
125
    let mut arguments: [abi::Handle; 8] = undefined;
126
    let mut handles: [abi::Handle; 8] = undefined;
127
    let mut contexts: [abi::Ref; 8] = undefined;
128
    let mut count: u64 = 0;
129
    for hart in 0..8 {
130
        if (boot::PLATFORM.harts & (1 << hart)) == 0 { continue; }
131
        set count += 1;
132
        set arguments[hart] = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1);
133
        set ARGUMENTS[hart] = (try! pages::get(&pages::STORE, (try! capability::get(&TABLE, arguments[hart])).object)).base;
134
    }
135
    set FREE = freeFrames();
136
    set SLOTS = capacity();
137
    for hart in 0..8 {
138
        if (boot::PLATFORM.harts & (1 << hart)) == 0 { continue; }
139
        let handle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
140
        let object = (try! capability::get(&TABLE, handle)).object;
141
        let mut child = try! domains::get(&domains::STORE, object);
142
        set CHILDREN[hart] = object; set handles[hart] = handle; set contexts[hart] = child.initial;
143
        try! domains::reparent(&mut domains::STORE, &TABLE, handle, parentHandle);
144
        let self = try! capability::install(&mut child.memory.table, capability::Entry {
145
            kind: abi::Kind::Domain, object, rights: abi::Rights(abi::CREATE | abi::ALLOCATE),
146
        });
147
        let stack = try! pages::allocate(&mut pages::STORE, &mut child.memory.table, self, 4);
148
        let storage = try! pages::get(&pages::STORE, (try! capability::get(&child.memory.table, stack)).object);
149
        let args = @sliceOf(memory(ARGUMENTS[hart]) as *mut u64, 6);
150
        set args[0] = *(try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, source, abi::READ as u64));
151
        set args[1] = dispatchinput::job.len as u64;
152
        for i in 0..devices::STORE.count {
153
            if devices::STORE.regions[i].kind == platform::Kind::Clint {
154
                set args[2] = *(try! devices::install(&devices::STORE, &mut child.memory.table, i));
155
            }
156
        }
157
        assert args[2] <> 0;
158
        set args[3] = *(try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, arguments[hart], (abi::READ | abi::WRITE | abi::GRANT) as u64));
159
        set args[4] = 10000000 * count;
160
        try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, handle, storage.base + storage.count as u64 * 4096, ARGUMENTS[hart], 56);
161
    }
162
    for byte in "cycles controllers ready\n" { put(byte); }
163
    let now = dispatch::clock();
164
    let start = now + 1000000 * count;
165
    for hart in 0..8 {
166
        if (boot::PLATFORM.harts & (1 << hart)) == 0 { continue; }
167
        let window = try! budgets::seed(&mut budgets::STORE, &mut TABLE, hart, start, 0xffffffffffffffff);
168
        let tail = try! budgets::split(&mut budgets::STORE, &mut TABLE, window, start + 800000000 * count, now);
169
        let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
170
            budgets::Binding { budget: window, domain: handles[hart], context: contexts[hart] }, now);
171
        if hart == 0 {
172
            let final = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
173
                budgets::Binding { budget: tail, domain: parentHandle, context: parent.initial }, now);
174
        }
175
    }
176
}
177
178
/// Check all terminal records, shared code identity, and complete transient recovery.
179
export unsafe fn verify() {
180
    for byte in "cycles checking completion\n" { put(byte); }
181
    let guard = sync::enter();
182
    let mut parent = try! domains::get(&domains::STORE, PARENT);
183
    let job = registry::find(&registry::STORE, &"job"[..]) else panic "worker package required";
184
    let package = try! registry::get(&registry::STORE, job);
185
    let mut seen: u64 = 0;
186
    while let event = try! events::pop(&mut parent.memory.ring) {
187
        assert event.kind == events::CHILD_EXIT and event.code == 68;
188
        let mut found = false;
189
        for hart in 0..8 {
190
            if (boot::PLATFORM.harts & (1 << hart)) == 0 { continue; }
191
            if event.value == abi::id(CHILDREN[hart]) {
192
                assert (seen & (1 << hart)) == 0;
193
                set seen |= 1 << hart; set found = true;
194
                let args = @sliceOf(memory(ARGUMENTS[hart]) as *mut u64, 7);
195
                assert args[5] == package.codeAddress and args[6] == 4;
196
            }
197
        }
198
        assert found;
199
    }
200
    assert seen == boot::PLATFORM.harts;
201
    try! events::refresh(&mut domains::STORE.events, PARENT, &parent.memory.ring);
202
    assert loader::STATE.live[job.index] and not loader::STATE.busy;
203
    let retained = loader::STATE.resident[job.index].code.count + loader::STATE.resident[job.index].metadata.count;
204
    sync::leave(guard);
205
    let mut done = false;
206
    for attempt in 0..100000 {
207
        let guard = sync::enter();
208
        set done = domains::STORE.dead == 0 and pages::STORE.backings.pool.retiredCount == 0;
209
        if done { sync::leave(guard); break; }
210
        let request = try! dispatch::request(0, remote::Action::Reschedule);
211
        sync::leave(guard);
212
        assert try! dispatch::awaitRequest(0, request) == 0;
213
    }
214
    assert done;
215
    assert freeFrames() + retained == FREE;
216
    let recovered = capacity();
217
    for i in 0..4 { assert recovered[i] == SLOTS[i]; }
218
    invariants::check(&TABLE);
219
    for byte in "cycles final recovery and invariants passed\n" { put(byte); }
220
    let maximum = sync::maximum();
221
    assert maximum > 0 and maximum < 1000000;
222
    for byte in "cycles metadata instructions: " { put(byte); }
223
    number(maximum);
224
    put(10);
225
    let waiting = sync::maximumWait();
226
    assert waiting > 0;
227
    for byte in "cycles acquisition instructions: " { put(byte); }
228
    number(waiting);
229
    put(10);
230
    finish();
231
}
232
233
/// Write a fixed-width diagnostic value.
234
fn number(value: u64) {
235
    let digits = "0123456789abcdef";
236
    for i in 0..16 { put(digits[((value >> ((15 - i) as u64 * 4)) & 15) as u32]); }
237
}