compiler/
kernel/
lib/
scripts/
seed/
sublime/
test/
acceptance/
boot/
bootstrap/
cycles/
dispatch/
loader/
mmio/
modules/
native/
packages/
pages/
runtime/
scheduling/
shared/
app.rad
601 B
build.rad
6.3 KiB
run
636 B
support.rad
419 B
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/shared/build.rad
raw
| 1 | //! Build a machine fixture from separately decoded and linked packages. |
| 2 | |
| 3 | use std::sys; |
| 4 | use std::sys::unix; |
| 5 | use std::mem; |
| 6 | use std::lang::alloc; |
| 7 | use std::lang::il::binary; |
| 8 | use std::lang::il::binary::program; |
| 9 | use std::lang::gen::data; |
| 10 | use std::arch::rv64; |
| 11 | use std::arch::rv64::shared; |
| 12 | use std::arch::rv64::emit; |
| 13 | use std::arch::rv64::encode; |
| 14 | use std::arch::rv64::image; |
| 15 | |
| 16 | /// Separate code arenas preserve the boot catalog's package records. |
| 17 | unsafe static CODE: [[u8; 16777216]; 3] = undefined; |
| 18 | /// Reusable function workspace. |
| 19 | static SCRATCH: [u8; 16777216] = [0; 16777216]; |
| 20 | /// Decoder arena shared by the two input packages. |
| 21 | static DECODE: [u8; 1048576] = [0; 1048576]; |
| 22 | /// Input file buffer. |
| 23 | static INPUT: [u8; 65536] = [0; 65536]; |
| 24 | /// Persistent private templates. |
| 25 | unsafe static TEMPLATES: [[u8; 16384]; 2] = undefined; |
| 26 | /// Local symbol workspaces. |
| 27 | unsafe static SYMBOLS: [[shared::Symbol; 128]; 2] = undefined; |
| 28 | /// Package exports. |
| 29 | unsafe static EXPORTS: [[shared::Symbol; 128]; 2] = undefined; |
| 30 | /// Private pointer fixups. |
| 31 | unsafe static RELOCS: [[shared::Relocation; 128]; 2] = undefined; |
| 32 | /// Data layout workspaces. |
| 33 | unsafe static DATA: [[data::DataSym; 128]; 2] = undefined; |
| 34 | /// Native instruction image, with fixed package placements. |
| 35 | static TEXT: [u32; 4096] = [0; 4096]; |
| 36 | /// Two private graphs followed by their package-state tables. |
| 37 | static STATE: [u8; 69632] = [0; 69632]; |
| 38 | |
| 39 | /// Decode trusted package IL into persistent storage. |
| 40 | unsafe fn load(path: *[u8], arena: &mut alloc::Arena) -> binary::Package { |
| 41 | let length = unix::readFile(path, &mut INPUT[..]) else panic "missing package"; |
| 42 | return try! program::decode(&INPUT[..length], arena, binary::Limits { registers: 8192, blocks: 4096 }); |
| 43 | } |
| 44 | |
| 45 | /// Compile through the same entry used for boot catalogs and runtime loading. |
| 46 | unsafe fn compile(input: &binary::Package, index: u32, imports: &[shared::Symbol]) -> shared::Package throws (shared::Error) { |
| 47 | let mut arena = alloc::new(&mut CODE[index][..]); |
| 48 | let mut scratch = alloc::new(&mut SCRATCH[..]); |
| 49 | return try shared::compile(input, index, 0x80011000 + index as u64 * 4096, imports, |
| 50 | shared::Storage { |
| 51 | data: &mut DATA[index][..], symbols: &mut SYMBOLS[index][..], exports: &mut EXPORTS[index][..], |
| 52 | template: &mut TEMPLATES[index][..], relocations: &mut RELOCS[index][..], |
| 53 | }, &mut arena, &mut scratch); |
| 54 | } |
| 55 | |
| 56 | /// Append a call result check and return its branch patch location. |
| 57 | fn check(e: &mut emit::Emitter, entry: u64, expected: i64) -> u32 { |
| 58 | let delta = entry - (0x80010000 + e.codeLen as u64 * 4); |
| 59 | emit::emit(e, encode::jal(rv64::RA, delta as i32)); |
| 60 | emit::loadImm(e, rv64::T0, expected); |
| 61 | let index = e.codeLen; |
| 62 | emit::emit(e, encode::nop()); |
| 63 | return index; |
| 64 | } |
| 65 | |
| 66 | /// Emit an explicit platform completion status. |
| 67 | fn finish(e: &mut emit::Emitter, status: i64) { |
| 68 | emit::loadImm(e, rv64::T0, 0x10001000); |
| 69 | emit::loadImm(e, rv64::T1, status); |
| 70 | emit::emit(e, encode::sw(rv64::T1, rv64::T0, 0)); |
| 71 | emit::emit(e, encode::ebreak()); |
| 72 | } |
| 73 | |
| 74 | /// Verify catalog linking, then execute one code copy against two private graphs. |
| 75 | @default unsafe fn main(env: *sys::Env) -> i32 { |
| 76 | assert env.args.len == 4; |
| 77 | let mut decoder = alloc::new(&mut DECODE[..]); |
| 78 | let supportInput = load(env.args[1], &mut decoder); |
| 79 | let appInput = load(env.args[2], &mut decoder); |
| 80 | let support = try! compile(&supportInput, 0, &[]); |
| 81 | let mut far: [shared::Symbol; 128] = undefined; |
| 82 | for symbol, i in support.exports { |
| 83 | set far[i] = symbol; |
| 84 | match symbol.target { |
| 85 | case shared::Target::Function(_) => { set far[i].target = shared::Target::Function(0x180000000); }, |
| 86 | else => {}, |
| 87 | } |
| 88 | } |
| 89 | let mut rejected = false; |
| 90 | try compile(&appInput, 1, &far[..support.exports.len]) catch err { |
| 91 | assert err == shared::Error::Range; |
| 92 | set rejected = true; |
| 93 | }; |
| 94 | assert rejected; |
| 95 | let app = try! compile(&appInput, 1, support.exports); |
| 96 | let catalog = [support, app]; |
| 97 | assert app.relocations.len > 0; |
| 98 | let entry = app.entry else panic "missing entry"; |
| 99 | for i in 0..STATE.len { set STATE[i] = 0; } |
| 100 | for domain in 0..2 { |
| 101 | let mut bases: [u64; 256] = [0; 256]; |
| 102 | for package, i in &catalog[..] { |
| 103 | let offset = domain * 32768 + i * 16384; |
| 104 | set bases[i] = 0x80020000 + offset as u64; |
| 105 | } |
| 106 | for package, i in &catalog[..] { |
| 107 | let offset = domain * 32768 + i * 16384; |
| 108 | try! shared::instantiate(&package, &bases[..], &mut STATE[offset..offset + 16384]); |
| 109 | } |
| 110 | let table = @sliceOf(&bases[0] as *unsafe u8, @sizeOf([u64; 256])); |
| 111 | let tableOffset: u32 = 65536 + domain * 2048; |
| 112 | try! mem::copy(&mut STATE[tableOffset..], table); |
| 113 | } |
| 114 | let mut arena = alloc::new(&mut CODE[2][..]); |
| 115 | let mut e = try! emit::emitter(&mut arena, false); |
| 116 | emit::loadImm(&mut e, rv64::GP, 0x80030000); |
| 117 | let first = check(&mut e, entry, 142); |
| 118 | let second = check(&mut e, entry, 143); |
| 119 | emit::loadImm(&mut e, rv64::GP, 0x80030800); |
| 120 | let other = check(&mut e, entry, 142); |
| 121 | emit::loadImm(&mut e, rv64::GP, 0x80030000); |
| 122 | let resumed = check(&mut e, entry, 144); |
| 123 | finish(&mut e, 0x5555); |
| 124 | let failure = e.codeLen; |
| 125 | finish(&mut e, 0x13333); |
| 126 | for index in &[first, second, other, resumed] { |
| 127 | emit::patch(&mut e, index, encode::bne(rv64::A0, rv64::T0, (failure - index) as i32 * 4)); |
| 128 | } |
| 129 | for i in 0..TEXT.len { set TEXT[i] = encode::nop(); } |
| 130 | assert e.codeLen <= 1024; |
| 131 | for word, i in emit::getCode(&e) { set TEXT[i] = word; } |
| 132 | for package, i in &catalog[..] { |
| 133 | assert package.code.len <= 1024; |
| 134 | for word, j in package.code { set TEXT[1024 + i * 1024 + j] = word; } |
| 135 | } |
| 136 | let header = try! image::header(image::Layout { |
| 137 | entry: 0x80010000, |
| 138 | code: image::Segment { address: 0x80010000, initialized: 16384, memory: 16384 }, |
| 139 | roData: image::Segment { address: 0, initialized: 0, memory: 0 }, |
| 140 | rwData: image::Segment { address: 0x80020000, initialized: STATE.len, memory: STATE.len }, |
| 141 | }); |
| 142 | let fd = unix::openOpts(env.args[3], unix::OpenFlags(*unix::O_WRONLY | *unix::O_CREAT | *unix::O_TRUNC), 420); |
| 143 | assert fd >= 0; |
| 144 | let written = unix::writeAll(fd, &header[..]) and unix::writeAll(fd, @sliceOf(&TEXT[0] as *u8, 16384)) and unix::writeAll(fd, &STATE[..]); |
| 145 | let closed = unix::close(fd) == 0; |
| 146 | assert written and closed; |
| 147 | return 0; |
| 148 | } |