compiler/
kernel/
lib/
scripts/
seed/
sublime/
test/
acceptance/
boot/
bootstrap/
cycles/
dispatch/
kernel/
dispatchcheck.rad
9.0 KiB
machine.ras
1.5 KiB
run
2.2 KiB
spin.rad
7.3 KiB
loader/
mmio/
native/
packages/
pages/
runtime/
scheduling/
shared/
slots/
smp/
support/
sync/
termination/
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/dispatch/kernel/dispatchcheck.rad
raw
| 1 | //! Native timer preemption across user execution, idle, and machine continuations. |
| 2 | use std::mem; |
| 3 | use std::arch::rv64::shared; |
| 4 | use kernel::abi; |
| 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::events; |
| 16 | use kernel::sync; |
| 17 | use kernel::dispatchinput; |
| 18 | |
| 19 | /// Bootstrap authority used to create fixture domains and CPU windows. |
| 20 | unsafe static TABLE: capability::Table = undefined; |
| 21 | /// Domain handles used for budget binding. |
| 22 | unsafe static HANDLES: [abi::Handle; 3] = undefined; |
| 23 | /// Initial contexts for the user, machine worker, and completion check. |
| 24 | unsafe static CONTEXTS: [abi::Ref; 3] = undefined; |
| 25 | /// View a validated allocated source page. |
| 26 | fn memory(address: u64) -> *mut u8; |
| 27 | /// Current kernel package-state base. |
| 28 | fn kernelGp() -> u64; |
| 29 | /// Native entry for retained M-mode work. |
| 30 | fn worker() -> u64; |
| 31 | /// Native entry for the final assertion callback. |
| 32 | fn completion() -> u64; |
| 33 | /// Complete the machine fixture with a passing status. |
| 34 | fn finish(); |
| 35 | /// Complete the fixture with a distinct failed invariant code. |
| 36 | fn failed(code: u64); |
| 37 | |
| 38 | /// Prepare real private domains before enabling dispatch on hart zero. |
| 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 sourceEntry = try! capability::get(&TABLE, source); |
| 49 | let page = try! pages::get(&pages::STORE, sourceEntry.object); |
| 50 | let bytes = @sliceOf(memory(page.base), page.count * 4096); |
| 51 | let length = try! mem::copy(&mut bytes[..], &dispatchinput::INPUT[..]); |
| 52 | let image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE, |
| 53 | loader::Request { authority, source, offset: 0, length: length as u64 }); |
| 54 | for i in 0..3 { |
| 55 | set HANDLES[i] = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, ®istry::STORE, &mut TABLE, authority, image); |
| 56 | let cap = try! capability::get(&TABLE, HANDLES[i]); |
| 57 | let child = try! domains::get(&domains::STORE, cap.object); |
| 58 | set CONTEXTS[i] = child.initial; |
| 59 | if i > 0 { |
| 60 | set domains::STORE.records[cap.object.index].state = domains::Lifecycle::Active; |
| 61 | set domains::STORE.contexts[child.initial.index].frame.status = 0x1880; |
| 62 | set domains::STORE.contexts[child.initial.index].frame.registers[2] = domains::STORE.contexts[child.initial.index].kernelStack.end; |
| 63 | set domains::STORE.contexts[child.initial.index].frame.registers[3] = kernelGp(); |
| 64 | } |
| 65 | } |
| 66 | let cap = try! capability::get(&TABLE, HANDLES[0]); |
| 67 | let mut user = try! domains::get(&domains::STORE, cap.object); |
| 68 | let selfAuthority = try! capability::install(&mut user.memory.table, capability::Entry { |
| 69 | kind: abi::Kind::Domain, object: cap.object, rights: abi::Rights(abi::CREATE | abi::ALLOCATE | abi::EXECUTE | abi::WAKE | abi::DESTROY), |
| 70 | }); |
| 71 | let root = user.image; |
| 72 | let executable = try! registry::install(®istry::STORE, &mut user.memory.table, root); |
| 73 | let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1); |
| 74 | let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut user.memory.table, stack, (abi::READ | abi::WRITE) as u64); |
| 75 | let stackCap = try! capability::get(&TABLE, stack); |
| 76 | let stackPage = try! pages::get(&pages::STORE, stackCap.object); |
| 77 | let parent = try! capability::install(&mut user.memory.table, capability::Entry { |
| 78 | kind: abi::Kind::Domain, object: domains::STORE.contexts[CONTEXTS[2].index].owner, rights: abi::Rights(abi::WAKE), |
| 79 | }); |
| 80 | let args = @sliceOf(memory(stackPage.base), 40); |
| 81 | let words = [*granted, *executable, *selfAuthority]; |
| 82 | for word in 0..3 { |
| 83 | for byte in 0..8 { |
| 84 | set args[word * 8 + byte] = (words[word] >> (byte as u64 * 8)) as u8; |
| 85 | } |
| 86 | } |
| 87 | for byte in 0..8 { |
| 88 | set args[32 + byte] = (*parent >> (byte as u64 * 8)) as u8; |
| 89 | } |
| 90 | try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, HANDLES[0], stackPage.base + 4096, stackPage.base, 40); |
| 91 | let imageRef = try! registry::image(®istry::STORE, &TABLE, image, abi::Rights(abi::EXECUTE)); |
| 92 | let target = try! registry::exported(®istry::STORE, imageRef, &"spin::count"[..]); |
| 93 | let case shared::Target::Data(data) = target else panic "counter"; |
| 94 | let timer = try! dispatch::timer(&boot::PLATFORM, 0); |
| 95 | let clock = dispatch::now(timer); |
| 96 | let start = clock + 1000000; |
| 97 | let span: u64 = 8000000; |
| 98 | set domains::STORE.contexts[CONTEXTS[1].index].frame.pc = worker(); |
| 99 | set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[10] = user.graph.table[data.slot] + data.offset as u64; |
| 100 | set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[11] = timer.clock; |
| 101 | set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[12] = start + 3 * span; |
| 102 | set domains::STORE.contexts[CONTEXTS[1].index].frame.registers[13] = start + 4 * span; |
| 103 | set domains::STORE.contexts[CONTEXTS[2].index].frame.pc = completion(); |
| 104 | let mut windows: [abi::Handle; 6] = undefined; |
| 105 | let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, start + 6 * span); |
| 106 | for i in 0..6 { |
| 107 | set windows[i] = remaining; |
| 108 | if i < 5 { |
| 109 | set remaining = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + (i as u64 + 1) * span, clock); |
| 110 | } |
| 111 | } |
| 112 | let owners = &[0 as u32, 0, 1, 0, 1, 2]; |
| 113 | for i in 0..6 { |
| 114 | if i == 1 { |
| 115 | continue; |
| 116 | } |
| 117 | let owner = owners[i]; |
| 118 | let handle = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE, |
| 119 | budgets::Binding { budget: windows[i], domain: HANDLES[owner], context: CONTEXTS[owner] }, clock); |
| 120 | if i == 3 { |
| 121 | for byte in 0..8 { |
| 122 | set args[24 + byte] = (*handle >> (byte as u64 * 8)) as u8; |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | /// Check state captured by production timer handling after both resumptions. |
| 129 | export unsafe fn verify() { |
| 130 | let user = domains::STORE.contexts[CONTEXTS[0].index].frame; |
| 131 | let machine = domains::STORE.contexts[CONTEXTS[1].index].frame; |
| 132 | assert (user.status & 0x1800) == 0 and (machine.status & 0x1800) == 0x1800; |
| 133 | assert machine.registers[8] > 0 and machine.registers[9] == 1 and machine.registers[18] > 0; |
| 134 | let mut domain = try! domains::get(&domains::STORE, domains::STORE.contexts[CONTEXTS[0].index].owner); |
| 135 | let target = try! registry::exported(®istry::STORE, domain.image, &"spin::extraCount"[..]); |
| 136 | let case shared::Target::Data(data) = target else panic "extra counter"; |
| 137 | let bytes = @sliceOf(memory(domain.graph.table[data.slot] + data.offset as u64), 8); |
| 138 | let mut progress: u64 = 0; |
| 139 | for byte in 0..8 { |
| 140 | set progress |= bytes[byte] as u64 << (byte as u64 * 8); |
| 141 | } |
| 142 | if progress == 0 { |
| 143 | failed(6); |
| 144 | } |
| 145 | let checked = try! registry::exported(®istry::STORE, domain.image, &"spin::destroyed"[..]); |
| 146 | let case shared::Target::Data(flag) = checked else panic "destruction flag"; |
| 147 | if *memory(domain.graph.table[flag.slot] + flag.offset as u64) <> 1 { |
| 148 | failed(7); |
| 149 | } |
| 150 | let child = try! registry::exported(®istry::STORE, domain.image, &"spin::childId"[..]); |
| 151 | let case shared::Target::Data(identity) = child else panic "child identity"; |
| 152 | let idBytes = @sliceOf(memory(domain.graph.table[identity.slot] + identity.offset as u64), 8); |
| 153 | let mut childId: u64 = 0; |
| 154 | for byte in 0..8 { |
| 155 | set childId |= idBytes[byte] as u64 << (byte as u64 * 8); |
| 156 | } |
| 157 | let owner = domains::STORE.contexts[CONTEXTS[2].index].owner; |
| 158 | let guard = sync::enter(); |
| 159 | let mut checker = try! domains::get(&domains::STORE, owner); |
| 160 | assert try! events::flush(&mut domains::STORE.events, owner, &mut checker.memory.ring) == 0; |
| 161 | assert not try! events::acknowledged(&domains::STORE.events, abi::reference(childId)); |
| 162 | let exited = try! events::pop(&mut checker.memory.ring) else panic "child exit"; |
| 163 | assert exited.kind == events::CHILD_EXIT and exited.code == 0 and exited.value == childId; |
| 164 | try! events::refresh(&mut domains::STORE.events, owner, &checker.memory.ring); |
| 165 | assert try! events::acknowledged(&domains::STORE.events, abi::reference(childId)); |
| 166 | sync::leave(guard); |
| 167 | let wake = try! events::pop(&mut domain.memory.ring) else panic "wake token"; |
| 168 | assert wake.kind == events::WAKEUP and wake.code == 123; |
| 169 | let timeout = try! events::pop(&mut domain.memory.ring) else panic "timeout token"; |
| 170 | assert timeout.kind == events::TIMEOUT and timeout.code == 77 and timeout.value == 0; |
| 171 | assert try! events::pop(&mut domain.memory.ring) == nil; |
| 172 | finish(); |
| 173 | } |