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