test/shared/build.rad 6.3 KiB 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
}