test/mmio/kernel/dispatchcheck.rad 7.1 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 {
72
            set clockDevice = i;
73
        }
74
        if devices::STORE.regions[i].kind == platform::Kind::Finish {
75
            set finish = i;
76
        }
77
    }
78
    let mut handles: [abi::Handle; 9] = undefined;
79
    let mut contexts: [abi::Ref; 9] = undefined;
80
    for i in 0..9 {
81
        let handle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, &registry::STORE, &mut TABLE, authority, image);
82
        let object = (try! capability::get(&TABLE, handle)).object;
83
        let mut child = try! domains::get(&domains::STORE, object);
84
        set CHILDREN[i] = object;
85
        set handles[i] = handle;
86
        set contexts[i] = child.initial;
87
        try! domains::reparent(&mut domains::STORE, &TABLE, handle, parentHandle);
88
        let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1);
89
        let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, stack, (abi::READ | abi::WRITE) as u64);
90
        let storage = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, stack)).object);
91
        let mut region = scratch;
92
        if i == 2 or i == 6 {
93
            set region = finish;
94
        }
95
        let mut device = try! devices::install(&devices::STORE, &mut child.memory.table, region);
96
        let slot = (try! abi::decode(device)).object.index;
97
        if i == 2 {
98
            set child.memory.table.entries[slot].rights = abi::Rights(abi::READ);
99
        }
100
        if i == 3 {
101
            set child.memory.table.entries[slot].rights = abi::Rights(abi::WRITE);
102
        }
103
        if i == 1 {
104
            set device = abi::Handle(0);
105
        }
106
        if i == 7 {
107
            set device = granted;
108
        }
109
        let timerHandle = try! devices::install(&devices::STORE, &mut child.memory.table, clockDevice);
110
        let args = @sliceOf(memory(storage.base) as *mut u64, 2);
111
        set args[0] = *device; set args[1] = *timerHandle;
112
        let size = 16 + i as u64;
113
        try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, handle, storage.base + 4096, storage.base, size);
114
    }
115
    let timer = try! dispatch::timer(&boot::PLATFORM, 0);
116
    let clock = dispatch::now(timer);
117
    let start = clock + 1000000;
118
    let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, start + 20000000);
119
    for i in 0..9 {
120
        let next = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + (i as u64 + 1) * 2000000, clock);
121
        let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
122
            budgets::Binding { budget: remaining, domain: handles[i], context: contexts[i] }, clock);
123
        set remaining = next;
124
    }
125
    let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE,
126
        budgets::Binding { budget: remaining, domain: parentHandle, context: parent.initial }, clock);
127
}
128
129
/// Check each terminal kind, status, and generation while the parent continues to run.
130
export unsafe fn verify() {
131
    let guard = sync::enter();
132
    let mut parent = try! domains::get(&domains::STORE, PARENT);
133
    let codes = [61 as u32, 256, 256, 256, 256, 256, 256, 256, 256];
134
    for i in 0..9 {
135
        let event = try! events::pop(&mut parent.memory.ring) else panic "missing termination event";
136
        assert event.value == abi::id(CHILDREN[i]) and event.code == codes[i];
137
        if i == 0 {
138
            assert event.kind == events::CHILD_EXIT;
139
        }
140
        else {
141
            assert event.kind == events::FAULT;
142
        }
143
        assert domains::STORE.records[CHILDREN[i].index].state == domains::Lifecycle::Dead;
144
    }
145
    try! events::refresh(&mut domains::STORE.events, PARENT, &parent.memory.ring);
146
    assert try! events::pop(&mut parent.memory.ring) == nil;
147
    sync::leave(guard);
148
    finish();
149
}