test/mmio/kernel/dispatchcheck.rad 6.9 KiB raw
1
//! Native fixed-width MMIO and authority rejection before register access.
2
use std::mem;
3
use kernel::abi;
4
use kernel::slots;
5
use kernel::backing;
6
use kernel::pages;
7
use kernel::capability;
8
use kernel::registry;
9
use kernel::loader;
10
use kernel::domains;
11
use kernel::budgets;
12
use kernel::dispatch;
13
use kernel::boot;
14
use kernel::events;
15
use kernel::sync;
16
use kernel::dispatchinput;
17
use kernel::devices;
18
use kernel::platform;
19
20
/// Register storage exposed only through a synthetic Device capability.
21
static REGISTERS: [u64; 512] = [0; 512];
22
23
/// Bootstrap creation, allocation, and budget authority.
24
unsafe static TABLE: capability::Table = undefined;
25
/// Child domain identities retained by terminal events.
26
unsafe static CHILDREN: [abi::Ref; 9] = undefined;
27
/// Surviving event receiver and native completion checker.
28
unsafe static PARENT: abi::Ref = undefined;
29
/// Map a validated physical page.
30
fn memory(address: u64) -> *mut u8;
31
/// Current kernel package-state base.
32
fn kernelGp() -> u64;
33
/// Native entry for the completion checker.
34
fn completion() -> u64;
35
/// Signal successful completion to the machine fixture.
36
fn finish();
37
38
/// Give each child a disjoint window, followed by the surviving parent.
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 page = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, source)).object);
49
    let bytes = @sliceOf(memory(page.base), page.count * 4096);
50
    let length = try! mem::copy(&mut bytes[..], &dispatchinput::INPUT[..]);
51
    let image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE,
52
        loader::Request { authority, source, offset: 0, length: length as u64 });
53
    let parentHandle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
54
    set PARENT = (try! capability::get(&TABLE, parentHandle)).object;
55
    let parent = try! domains::get(&domains::STORE, PARENT);
56
    set domains::STORE.records[PARENT.index].state = domains::Lifecycle::Active;
57
    set domains::STORE.contexts[parent.initial.index].frame.pc = completion();
58
    set domains::STORE.contexts[parent.initial.index].frame.status = 0x1880;
59
    set domains::STORE.contexts[parent.initial.index].frame.registers[2] = domains::STORE.contexts[parent.initial.index].kernelStack.end;
60
    set domains::STORE.contexts[parent.initial.index].frame.registers[3] = kernelGp();
61
    let scratch = devices::STORE.count;
62
    set devices::STORE.regions[scratch] = {
63
        kind: platform::Kind::Uart,
64
        info: { base: (&mut REGISTERS[0]) as u64, size: 4096 },
65
        rights: abi::Rights(abi::READ | abi::WRITE | abi::GRANT | abi::TRANSFER),
66
    };
67
    set devices::STORE.count += 1;
68
    let mut clockDevice: u32 = 0;
69
    let mut finish: u32 = 0;
70
    for i in 0..scratch {
71
        if devices::STORE.regions[i].kind == platform::Kind::Clint { set clockDevice = i; }
72
        if devices::STORE.regions[i].kind == platform::Kind::Finish { set finish = i; }
73
    }
74
    let mut handles: [abi::Handle; 9] = undefined;
75
    let mut contexts: [abi::Ref; 9] = undefined;
76
    for i in 0..9 {
77
        let handle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
78
        let object = (try! capability::get(&TABLE, handle)).object;
79
        let mut child = try! domains::get(&domains::STORE, object);
80
        set CHILDREN[i] = object;
81
        set handles[i] = handle;
82
        set contexts[i] = child.initial;
83
        try! domains::reparent(&mut domains::STORE, &TABLE, handle, parentHandle);
84
        let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1);
85
        let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, stack, (abi::READ | abi::WRITE) as u64);
86
        let storage = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, stack)).object);
87
        let mut region = scratch;
88
        if i == 2 or i == 6 { set region = finish; }
89
        let mut device = try! devices::install(&devices::STORE, &mut child.memory.table, region);
90
        let slot = (try! abi::decode(device)).object.index;
91
        if i == 2 { set child.memory.table.entries[slot].rights = abi::Rights(abi::READ); }
92
        if i == 3 { set child.memory.table.entries[slot].rights = abi::Rights(abi::WRITE); }
93
        if i == 1 { set device = abi::Handle(0); }
94
        if i == 7 { set device = granted; }
95
        let timerHandle = try! devices::install(&devices::STORE, &mut child.memory.table, clockDevice);
96
        let args = @sliceOf(memory(storage.base) as *mut u64, 2);
97
        set args[0] = *device; set args[1] = *timerHandle;
98
        let size = 16 + i as u64;
99
        try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, handle, storage.base + 4096, storage.base, size);
100
    }
101
    let timer = try! dispatch::timer(&boot::PLATFORM, 0);
102
    let clock = dispatch::now(timer);
103
    let start = clock + 1000000;
104
    let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, start + 20000000);
105
    for i in 0..9 {
106
        let next = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + (i as u64 + 1) * 2000000, clock);
107
        let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
108
            budgets::Binding { budget: remaining, domain: handles[i], context: contexts[i] }, clock);
109
        set remaining = next;
110
    }
111
    let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
112
        budgets::Binding { budget: remaining, domain: parentHandle, context: parent.initial }, clock);
113
}
114
115
/// Check each terminal kind, status, and generation while the parent continues to run.
116
export unsafe fn verify() {
117
    let guard = sync::enter();
118
    let mut parent = try! domains::get(&domains::STORE, PARENT);
119
    let codes = [61 as u32, 256, 256, 256, 256, 256, 256, 256, 256];
120
    for i in 0..9 {
121
        let event = try! events::pop(&mut parent.memory.ring) else panic "missing termination event";
122
        assert event.value == abi::id(CHILDREN[i]) and event.code == codes[i];
123
        if i == 0 { assert event.kind == events::CHILD_EXIT; }
124
        else { assert event.kind == events::FAULT; }
125
        assert domains::STORE.records[CHILDREN[i].index].state == domains::Lifecycle::Dead;
126
    }
127
    try! events::refresh(&mut domains::STORE.events, PARENT, &parent.memory.ring);
128
    assert try! events::pop(&mut parent.memory.ring) == nil;
129
    sync::leave(guard);
130
    finish();
131
}