test/bootstrap/kernel/dispatchcheck.rad 4.8 KiB raw
1
//! Native root construction, exit, and continued resource authority.
2
use kernel::abi;
3
use kernel::boot;
4
use kernel::registry;
5
use kernel::domains;
6
use kernel::capability;
7
use kernel::pages;
8
use kernel::budgets;
9
use kernel::dispatch;
10
use kernel::calls;
11
use kernel::events;
12
use kernel::sync;
13
use kernel::startup;
14
use kernel::devices;
15
use kernel::interrupts;
16
17
/// Initial root identity retained by the terminal event.
18
unsafe static ROOT: abi::Ref = undefined;
19
/// Surviving controller domain with inherited resource authority.
20
unsafe static CONTROLLER: abi::Ref = undefined;
21
/// Image capability installed in the controller's own table.
22
unsafe static IMAGE: abi::Handle = undefined;
23
/// Current kernel package-state table.
24
fn kernelGp() -> u64;
25
/// Controller entry address.
26
fn completion() -> u64;
27
/// Signal successful completion to the emulator.
28
fn finish();
29
/// Map an assembly-compatible physical byte address.
30
fn memory(address: u64) -> *mut u8;
31
32
/// Construct root from the boot catalog and give its child a later CPU window.
33
export unsafe fn setup() {
34
    let image = registry::find(&registry::STORE, &"loaded"[..]) else panic "missing boot user package";
35
    let service = registry::find(&registry::STORE, &"service"[..]) else panic "missing boot service package";
36
    set ROOT = try! startup::create(&boot::PLATFORM, image, service);
37
    assert ROOT.index == 0;
38
    let mut root = try! domains::get(&domains::STORE, ROOT);
39
    let self = try! abi::handle(abi::Kind::Domain, abi::Ref { index: 0, generation: root.memory.table.slots[0].generation });
40
    assert (try! abi::decode(root.events)).object.index == 1;
41
    let executable = try! registry::install(&registry::STORE, &mut root.memory.table, image);
42
    let childHandle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings,
43
        &registry::STORE, &mut root.memory.table, self, executable);
44
    set CONTROLLER = (try! capability::get(&root.memory.table, childHandle)).object;
45
    let mut child = try! domains::get(&domains::STORE, CONTROLLER);
46
    let inherited = domains::MANAGEMENT_RIGHTS | abi::CREATE | abi::ALLOCATE;
47
    let authority = try! calls::invoke(ROOT, 10, &[*childHandle, *childHandle, inherited as u64, 0], 0);
48
    assert service.index == 3 and image.index == 2;
49
    set IMAGE = try! registry::install(&registry::STORE, &mut child.memory.table, service);
50
    try! domains::reparent(&mut domains::STORE, &root.memory.table, self, childHandle);
51
    set domains::STORE.records[CONTROLLER.index].state = domains::Lifecycle::Active;
52
    let frame = &mut domains::STORE.contexts[child.initial.index].frame;
53
    set frame.pc = completion(); set frame.status = 0x1880;
54
    set frame.registers[2] = domains::STORE.contexts[child.initial.index].kernelStack.end;
55
    set frame.registers[3] = kernelGp();
56
    let now = dispatch::clock();
57
    let index = 2 + devices::STORE.count + interrupts::STORE.count;
58
    let budget = try! abi::handle(abi::Kind::Budget, abi::Ref { index, generation: root.memory.table.slots[index].generation });
59
    let window = try! budgets::query(&budgets::STORE, &root.memory.table, budget);
60
    let start = window.start;
61
    let later = try! budgets::split(&mut budgets::STORE, &mut root.memory.table, budget, start + 10000000, now);
62
    let running = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut root.memory.table,
63
        budgets::Binding { budget, domain: self, context: root.initial }, now);
64
    let transferred = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut root.memory.table,
65
        budgets::Binding { budget: later, domain: childHandle, context: child.initial }, now);
66
}
67
68
/// Root exit leaves the survivor able to allocate and create new domains.
69
export unsafe fn verify() {
70
    let guard = sync::enter();
71
    let mut child = try! domains::get(&domains::STORE, CONTROLLER);
72
    let terminal = try! events::pop(&mut child.memory.ring) else panic "missing root exit";
73
    assert terminal.kind == events::CHILD_EXIT and terminal.code == 0 and terminal.value == abi::id(ROOT);
74
    assert child.state == domains::Lifecycle::Active and child.parent == nil;
75
    try! events::refresh(&mut domains::STORE.events, CONTROLLER, &child.memory.ring);
76
    sync::leave(guard);
77
    let page = abi::Handle(try! calls::synchronized(CONTROLLER, 30, &[0, 1, 0, 0], dispatch::clock()));
78
    let domain = abi::Handle(try! calls::synchronized(CONTROLLER, 20, &[0, *IMAGE, 0, 0], dispatch::clock()));
79
    let checking = sync::enter();
80
    let allocated = try! capability::get(&child.memory.table, page);
81
    assert (try! pages::get(&pages::STORE, allocated.object)).count == 1;
82
    let object = (try! capability::get(&child.memory.table, domain)).object;
83
    let created = try! domains::get(&domains::STORE, object);
84
    assert created.creator == CONTROLLER and created.parent == CONTROLLER;
85
    assert created.state == domains::Lifecycle::Pending;
86
    sync::leave(checking);
87
    finish();
88
}