compiler/
kernel/
lib/
scripts/
seed/
sublime/
test/
acceptance/
boot/
bootstrap/
cycles/
dispatch/
loader/
mmio/
native/
packages/
pages/
runtime/
scheduling/
shared/
slots/
smp/
support/
sync/
termination/
kernel/
dispatchcheck.rad
6.1 KiB
machine.ras
683 B
spin.rad
1.1 KiB
tests/
trap/
package-golden
1.6 KiB
run
3.1 KiB
runner.rad
10.5 KiB
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
9.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 B
test/termination/kernel/dispatchcheck.rad
raw
| 1 | //! Native exit and fault reporting to a surviving parent. |
| 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 | /// Bootstrap creation, allocation, and budget authority. |
| 21 | unsafe static TABLE: capability::Table = undefined; |
| 22 | /// Child domain identities retained by terminal events. |
| 23 | unsafe static CHILDREN: [abi::Ref; 6] = undefined; |
| 24 | /// Surviving event receiver and native completion checker. |
| 25 | unsafe static PARENT: abi::Ref = undefined; |
| 26 | /// Map a validated physical page. |
| 27 | fn memory(address: u64) -> *mut u8; |
| 28 | /// Current kernel package-state base. |
| 29 | fn kernelGp() -> u64; |
| 30 | /// Native entry for the completion checker. |
| 31 | fn completion() -> u64; |
| 32 | /// Signal successful completion to the machine fixture. |
| 33 | fn finish(); |
| 34 | |
| 35 | /// Give each child a disjoint window, followed by the surviving parent. |
| 36 | export unsafe fn setup() { |
| 37 | let pending = try! slots::reserve(&mut domains::STORE.slots[..]); |
| 38 | let owner = try! slots::commit(&mut domains::STORE.slots[..], pending); |
| 39 | capability::initialize(&mut TABLE, owner); |
| 40 | try! backing::registerDomain(&mut pages::STORE.backings, owner); |
| 41 | let authority = try! capability::install(&mut TABLE, capability::Entry { |
| 42 | kind: abi::Kind::Domain, object: owner, rights: abi::Rights(abi::CREATE | abi::ALLOCATE), |
| 43 | }); |
| 44 | let source = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, (dispatchinput::INPUT.len as u64 + 4095) / 4096); |
| 45 | let page = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, source)).object); |
| 46 | let bytes = @sliceOf(memory(page.base), page.count * 4096); |
| 47 | let length = try! mem::copy(&mut bytes[..], &dispatchinput::INPUT[..]); |
| 48 | let image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE, |
| 49 | loader::Request { authority, source, offset: 0, length: length as u64 }); |
| 50 | let parentHandle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, ®istry::STORE, &mut TABLE, authority, image); |
| 51 | set PARENT = (try! capability::get(&TABLE, parentHandle)).object; |
| 52 | let parent = try! domains::get(&domains::STORE, PARENT); |
| 53 | set domains::STORE.records[PARENT.index].state = domains::Lifecycle::Active; |
| 54 | set domains::STORE.contexts[parent.initial.index].frame.pc = completion(); |
| 55 | set domains::STORE.contexts[parent.initial.index].frame.status = 0x1880; |
| 56 | set domains::STORE.contexts[parent.initial.index].frame.registers[2] = domains::STORE.contexts[parent.initial.index].kernelStack.end; |
| 57 | set domains::STORE.contexts[parent.initial.index].frame.registers[3] = kernelGp(); |
| 58 | let mut handles: [abi::Handle; 6] = undefined; |
| 59 | let mut contexts: [abi::Ref; 6] = undefined; |
| 60 | for i in 0..6 { |
| 61 | let handle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, ®istry::STORE, &mut TABLE, authority, image); |
| 62 | let object = (try! capability::get(&TABLE, handle)).object; |
| 63 | let mut child = try! domains::get(&domains::STORE, object); |
| 64 | set CHILDREN[i] = object; |
| 65 | set handles[i] = handle; |
| 66 | set contexts[i] = child.initial; |
| 67 | try! domains::reparent(&mut domains::STORE, &TABLE, handle, parentHandle); |
| 68 | let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1); |
| 69 | let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, stack, (abi::READ | abi::WRITE) as u64); |
| 70 | let storage = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, stack)).object); |
| 71 | let mut size = i as u64; |
| 72 | if i == 5 { |
| 73 | let mut installed = false; |
| 74 | for index in 0..devices::STORE.count { |
| 75 | if devices::STORE.regions[index].kind <> platform::Kind::Finish { |
| 76 | continue; |
| 77 | } |
| 78 | let device = try! devices::install(&devices::STORE, &mut child.memory.table, index); |
| 79 | let args = memory(storage.base) as *mut u64; |
| 80 | set *args = *device; |
| 81 | set installed = true; |
| 82 | break; |
| 83 | } |
| 84 | assert installed; |
| 85 | set size = 8; |
| 86 | } |
| 87 | try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, handle, storage.base + 4096, storage.base, size); |
| 88 | } |
| 89 | let timer = try! dispatch::timer(&boot::PLATFORM, 0); |
| 90 | let clock = dispatch::now(timer); |
| 91 | let start = clock + 1000000; |
| 92 | let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, start + 14000000); |
| 93 | for i in 0..6 { |
| 94 | let next = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + (i as u64 + 1) * 2000000, clock); |
| 95 | let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE, |
| 96 | budgets::Binding { budget: remaining, domain: handles[i], context: contexts[i] }, clock); |
| 97 | set remaining = next; |
| 98 | } |
| 99 | let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE, |
| 100 | budgets::Binding { budget: remaining, domain: parentHandle, context: parent.initial }, clock); |
| 101 | } |
| 102 | |
| 103 | /// Check each terminal kind, status, and generation while the parent continues to run. |
| 104 | export unsafe fn verify() { |
| 105 | let guard = sync::enter(); |
| 106 | let mut parent = try! domains::get(&domains::STORE, PARENT); |
| 107 | let codes = [37 as u32, abi::FAULT_ABORT, 3, 0, abi::FAULT_ABORT, 51]; |
| 108 | for i in 0..6 { |
| 109 | let event = try! events::pop(&mut parent.memory.ring) else panic "missing termination event"; |
| 110 | assert event.value == abi::id(CHILDREN[i]) and event.code == codes[i]; |
| 111 | if i == 0 or i == 3 or i == 5 { |
| 112 | assert event.kind == events::CHILD_EXIT; |
| 113 | } |
| 114 | else { |
| 115 | assert event.kind == events::FAULT; |
| 116 | } |
| 117 | assert domains::STORE.records[CHILDREN[i].index].state == domains::Lifecycle::Dead; |
| 118 | } |
| 119 | try! events::refresh(&mut domains::STORE.events, PARENT, &parent.memory.ring); |
| 120 | assert try! events::pop(&mut parent.memory.ring) == nil; |
| 121 | sync::leave(guard); |
| 122 | finish(); |
| 123 | } |