compiler/
kernel/
lib/
scripts/
seed/
sublime/
test/
acceptance/
boot/
bootstrap/
cycles/
dispatch/
loader/
mmio/
modules/
native/
packages/
pages/
runtime/
kernel/
dispatchcheck.rad
11.1 KiB
machine.ras
1.1 KiB
run
2.5 KiB
spin.rad
1.8 KiB
scheduling/
shared/
slots/
smp/
sync/
termination/
tests/
trap/
run
2.7 KiB
runner.rad
10.3 KiB
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
10.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
551 B
test/runtime/kernel/dispatchcheck.rad
raw
| 1 | //! Runtime compiler ownership across scheduled windows and domain destruction. |
| 2 | use std::mem; |
| 3 | use kernel::abi; |
| 4 | use kernel::frames; |
| 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::sync; |
| 16 | use kernel::calls; |
| 17 | use kernel::lifecycle; |
| 18 | use kernel::remote; |
| 19 | use kernel::dispatchinput; |
| 20 | |
| 21 | /// Bootstrap resource capabilities. |
| 22 | unsafe static TABLE: capability::Table = undefined; |
| 23 | /// First loader, retry loader, witness, and controller domain handles. |
| 24 | unsafe static HANDLES: [abi::Handle; 4] = undefined; |
| 25 | /// Generation-bearing domain identities for each actor. |
| 26 | unsafe static ACTORS: [abi::Ref; 4] = undefined; |
| 27 | /// Initial context identities for each actor. |
| 28 | unsafe static CONTEXTS: [abi::Ref; 4] = undefined; |
| 29 | /// Controller capability for the first loader. |
| 30 | unsafe static VICTIM: abi::Handle = undefined; |
| 31 | /// Controller capability for the binary input page. |
| 32 | unsafe static SOURCE: abi::Handle = undefined; |
| 33 | /// Shared user progress and published package identity. |
| 34 | unsafe static PROGRESS: *mut u64 = undefined; |
| 35 | /// Start of the controller's final execution window. |
| 36 | static FINAL: u64 = 0; |
| 37 | /// Write one diagnostic byte to the fixture UART. |
| 38 | fn put(byte: u8); |
| 39 | /// Write a fixed-width hexadecimal diagnostic value. |
| 40 | fn number(value: u64) { |
| 41 | let digits = "0123456789abcdef"; |
| 42 | for i in 0..16 { put(digits[((value >> ((15 - i) as u64 * 4)) & 15) as u32]); } |
| 43 | } |
| 44 | |
| 45 | /// Map a validated physical page. |
| 46 | fn memory(address: u64) -> *mut u8; |
| 47 | /// Current kernel package-state base. |
| 48 | fn kernelGp() -> u64; |
| 49 | /// Native controller entry address. |
| 50 | fn completion() -> u64; |
| 51 | /// Execute published code with one private package-state table. |
| 52 | fn invoke(address: u64, table: u64) -> i64; |
| 53 | /// Signal native fixture completion. |
| 54 | fn finish(); |
| 55 | |
| 56 | /// Copy trusted package bytes into a bootstrap-owned page allocation. |
| 57 | unsafe fn input(authority: abi::Handle, bytes: &[u8]) -> abi::Handle { |
| 58 | let handle = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, (bytes.len as u64 + 4095) / 4096); |
| 59 | let page = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, handle)).object); |
| 60 | let copied = try! mem::copy(@sliceOf(memory(page.base), page.count * 4096), bytes); |
| 61 | assert copied == bytes.len; |
| 62 | return handle; |
| 63 | } |
| 64 | |
| 65 | /// Install user actors and disjoint windows that interrupt two compiler calls. |
| 66 | export unsafe fn setup() { |
| 67 | let pending = try! slots::reserve(&mut domains::STORE.slots[..]); |
| 68 | let owner = try! slots::commit(&mut domains::STORE.slots[..], pending); |
| 69 | capability::initialize(&mut TABLE, owner); |
| 70 | try! backing::registerDomain(&mut pages::STORE.backings, owner); |
| 71 | let authority = try! capability::install(&mut TABLE, capability::Entry { |
| 72 | kind: abi::Kind::Domain, object: owner, rights: abi::Rights(abi::CREATE | abi::ALLOCATE), |
| 73 | }); |
| 74 | let source = input(authority, &dispatchinput::INPUT[..]); |
| 75 | let image = try! loader::load(&mut loader::STATE, &mut pages::STORE, &mut registry::STORE, &mut TABLE, |
| 76 | loader::Request { authority, source, offset: 0, length: dispatchinput::INPUT.len as u64 }); |
| 77 | let payload = input(authority, &dispatchinput::PAYLOAD[..]); |
| 78 | let progress = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1); |
| 79 | let shared = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, progress)).object); |
| 80 | set PROGRESS = memory(shared.base) as *mut u64; |
| 81 | for i in 0..4 { |
| 82 | let handle = try! domains::create(&mut domains::STORE, &mut pages::STORE.backings, ®istry::STORE, &mut TABLE, authority, image); |
| 83 | let object = (try! capability::get(&TABLE, handle)).object; |
| 84 | let mut child = try! domains::get(&domains::STORE, object); |
| 85 | let mut rights = abi::ALLOCATE; |
| 86 | if i == 3 { set rights |= abi::CREATE; } |
| 87 | let self = try! capability::install(&mut child.memory.table, capability::Entry { |
| 88 | kind: abi::Kind::Domain, object, rights: abi::Rights(rights), |
| 89 | }); |
| 90 | set HANDLES[i] = handle; set ACTORS[i] = object; set CONTEXTS[i] = child.initial; |
| 91 | let readable = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, payload, abi::READ as u64); |
| 92 | let writable = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, progress, (abi::READ | abi::WRITE) as u64); |
| 93 | if i == 3 { |
| 94 | set SOURCE = readable; |
| 95 | set VICTIM = try! capability::install(&mut child.memory.table, capability::Entry { |
| 96 | kind: abi::Kind::Domain, object: ACTORS[0], rights: abi::Rights(abi::DESTROY), |
| 97 | }); |
| 98 | set domains::STORE.records[object.index].state = domains::Lifecycle::Active; |
| 99 | let frame = &mut domains::STORE.contexts[child.initial.index].frame; |
| 100 | set frame.pc = completion(); set frame.status = 0x1880; |
| 101 | set frame.registers[2] = domains::STORE.contexts[child.initial.index].kernelStack.end; |
| 102 | set frame.registers[3] = kernelGp(); |
| 103 | continue; |
| 104 | } |
| 105 | let stack = try! pages::allocate(&mut pages::STORE, &mut TABLE, authority, 1); |
| 106 | let granted = try! pages::grant(&mut pages::STORE, &TABLE, &mut child.memory.table, stack, (abi::READ | abi::WRITE) as u64); |
| 107 | let storage = try! pages::get(&pages::STORE, (try! capability::get(&TABLE, stack)).object); |
| 108 | let args = @sliceOf(memory(storage.base) as *mut u64, 3); |
| 109 | set args[0] = *readable; set args[1] = dispatchinput::PAYLOAD.len as u64; set args[2] = shared.base; |
| 110 | try! domains::activate(&mut domains::STORE, &pages::STORE, &TABLE, handle, storage.base + 4096, storage.base, i as u64); |
| 111 | } |
| 112 | for byte in "runtime actors ready\n" { put(byte); } |
| 113 | let now = dispatch::clock(); |
| 114 | let start = now + 1000000; |
| 115 | set FINAL = start + 300000000; |
| 116 | let mut remaining = try! budgets::seed(&mut budgets::STORE, &mut TABLE, 0, start, FINAL + 10000000); |
| 117 | let actors = [0 as u32, 3, 1, 2, 1]; |
| 118 | let ends = [10000000 as u64, 50000000, 60000000, 62000000, 300000000]; |
| 119 | for i in 0..5 { |
| 120 | let next = try! budgets::split(&mut budgets::STORE, &mut TABLE, remaining, start + ends[i], now); |
| 121 | let actor = actors[i]; |
| 122 | let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE, |
| 123 | budgets::Binding { budget: remaining, domain: HANDLES[actor], context: CONTEXTS[actor] }, now); |
| 124 | set remaining = next; |
| 125 | } |
| 126 | let bound = try! budgets::bind(&mut budgets::STORE, &domains::STORE, &mut TABLE, |
| 127 | budgets::Binding { budget: remaining, domain: HANDLES[3], context: CONTEXTS[3] }, now); |
| 128 | } |
| 129 | |
| 130 | /// Verify cancellation, competing admission, progress, and resident code reuse. |
| 131 | export unsafe fn verify() { |
| 132 | for byte in "runtime admission metadata instructions: " { put(byte); } |
| 133 | number(sync::maximum()); put(10); |
| 134 | let admissionWait = sync::maximumWait(); |
| 135 | assert admissionWait > 0; |
| 136 | for byte in "runtime admission acquisition instructions: " { put(byte); } |
| 137 | number(admissionWait); put(10); |
| 138 | let progress = @sliceOf(PROGRESS, 4); |
| 139 | let guard = sync::enter(); |
| 140 | let first = CONTEXTS[0]; |
| 141 | for byte in "runtime first progress and owner: " { put(byte); } |
| 142 | number(progress[0]); put(32); number(abi::id(loader::STATE.owner)); put(10); |
| 143 | assert progress[0] == 1 and loader::STATE.busy and loader::STATE.owner == ACTORS[0]; |
| 144 | assert domains::STORE.contexts[first.index].reservation; |
| 145 | assert (domains::STORE.contexts[first.index].frame.status & 0x1800) == 0x1800; |
| 146 | let allocation = lifecycle::CALLS.records[first.index].allocation; |
| 147 | let mut loading: lifecycle::Loading = undefined; |
| 148 | match allocation { |
| 149 | case lifecycle::Allocation::Load(value) => { set loading = value; }, |
| 150 | else => panic "loader reservation required", |
| 151 | } |
| 152 | let output = loading.output else panic "compilation output required"; |
| 153 | sync::leave(guard); |
| 154 | let mut busy = false; |
| 155 | try calls::synchronized(ACTORS[3], 51, &[0, *SOURCE, 0, dispatchinput::PAYLOAD.len as u64], dispatch::clock()) catch error { |
| 156 | assert error == abi::Error::Busy; set busy = true; |
| 157 | }; |
| 158 | assert busy; |
| 159 | for byte in "runtime competing load rejected\n" { put(byte); } |
| 160 | let destroyed = try! calls::synchronized(ACTORS[3], 22, &[*VICTIM, 0, 0, 0], dispatch::clock()); |
| 161 | assert destroyed == 0; |
| 162 | let checking = sync::enter(); |
| 163 | let request = try! dispatch::request(0, remote::Action::Reschedule); |
| 164 | sync::leave(checking); |
| 165 | let result = try! dispatch::awaitRequest(0, request); |
| 166 | assert result == 0; |
| 167 | let cancelled = sync::enter(); |
| 168 | assert not loader::STATE.busy; |
| 169 | assert (lifecycle::CALLS.active[first.index / 32] & (1 << (first.index % 32))) == 0; |
| 170 | assert registry::STORE.slots[output.object.index].state == slots::State::Free; |
| 171 | sync::leave(cancelled); |
| 172 | let mut reclaimed = false; |
| 173 | for attempt in 0..10000 { |
| 174 | let guard = sync::enter(); |
| 175 | set reclaimed = pages::STORE.backings.pool.retiredCount == 0; |
| 176 | if reclaimed { sync::leave(guard); break; } |
| 177 | let request = try! dispatch::request(0, remote::Action::Reschedule); |
| 178 | sync::leave(guard); |
| 179 | let result = try! dispatch::awaitRequest(0, request); |
| 180 | assert result == 0; |
| 181 | } |
| 182 | assert reclaimed; |
| 183 | for run in [loading.input.frames, output.code, output.metadata] { |
| 184 | let mut offset: u32 = 0; |
| 185 | while offset < run.count { |
| 186 | let mut count = run.count - offset; |
| 187 | if count > 256 { set count = 256; } |
| 188 | let recovered = sync::enter(); |
| 189 | for i in run.first + offset..run.first + offset + count { assert frames::available(&pages::STORE.backings.pool, i); } |
| 190 | sync::leave(recovered); |
| 191 | set offset += count; |
| 192 | } |
| 193 | } |
| 194 | for byte in "runtime cancellation passed\n" { put(byte); } |
| 195 | while dispatch::clock() < FINAL {} |
| 196 | let complete = sync::enter(); |
| 197 | for byte in "runtime final progress: " { put(byte); } |
| 198 | for i in 0..4 { number(progress[i]); put(32); } |
| 199 | put(10); |
| 200 | assert progress[0] == 1 and progress[1] == 2 and progress[2] == 1; |
| 201 | assert not loader::STATE.busy; |
| 202 | let package = try! registry::get(®istry::STORE, abi::reference(progress[3])); |
| 203 | let entry = package.entry else panic "published entry required"; |
| 204 | let mut controller = try! domains::get(&domains::STORE, ACTORS[3]); |
| 205 | let image = try! registry::install(®istry::STORE, &mut controller.memory.table, abi::reference(progress[3])); |
| 206 | sync::leave(complete); |
| 207 | let handle = abi::Handle(try! calls::synchronized(ACTORS[3], 20, &[0, *image, 0, 0], dispatch::clock())); |
| 208 | let created = sync::enter(); |
| 209 | let object = (try! capability::get(&controller.memory.table, handle)).object; |
| 210 | let domain = try! domains::get(&domains::STORE, object); |
| 211 | sync::leave(created); |
| 212 | assert invoke(entry, domain.graph.table.ptr as u64) == 43; |
| 213 | assert invoke(entry, domain.graph.table.ptr as u64) == 85; |
| 214 | for byte in "runtime retry published executable code\n" { put(byte); } |
| 215 | let maximum = sync::maximum(); |
| 216 | for byte in "runtime metadata instructions: " { put(byte); } |
| 217 | number(maximum); put(10); |
| 218 | assert maximum > 0 and maximum < 1000000; |
| 219 | let waiting = sync::maximumWait(); |
| 220 | assert waiting > 0; |
| 221 | for byte in "runtime acquisition instructions: " { put(byte); } |
| 222 | number(waiting); put(10); |
| 223 | finish(); |
| 224 | } |