test/shared/build.rad 6.5 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(_) => {
86
                set far[i].target = shared::Target::Function(0x180000000);
87
            },
88
            else => {
89
            },
90
        }
91
    }
92
    let mut rejected = false;
93
    try compile(&appInput, 1, &far[..support.exports.len]) catch err {
94
        assert err == shared::Error::Range;
95
        set rejected = true;
96
    };
97
    assert rejected;
98
    let app = try! compile(&appInput, 1, support.exports);
99
    let catalog = [support, app];
100
    assert app.relocations.len > 0;
101
    let entry = app.entry else panic "missing entry";
102
    for i in 0..STATE.len {
103
        set STATE[i] = 0;
104
    }
105
    for domain in 0..2 {
106
        let mut bases: [u64; 256] = [0; 256];
107
        for package, i in &catalog[..] {
108
            let offset = domain * 32768 + i * 16384;
109
            set bases[i] = 0x80020000 + offset as u64;
110
        }
111
        for package, i in &catalog[..] {
112
            let offset = domain * 32768 + i * 16384;
113
            try! shared::instantiate(&package, &bases[..], &mut STATE[offset..offset + 16384]);
114
        }
115
        let table = @sliceOf(&bases[0] as *unsafe u8, @sizeOf([u64; 256]));
116
        let tableOffset: u32 = 65536 + domain * 2048;
117
        try! mem::copy(&mut STATE[tableOffset..], table);
118
    }
119
    let mut arena = alloc::new(&mut CODE[2][..]);
120
    let mut e = try! emit::emitter(&mut arena, false);
121
    emit::loadImm(&mut e, rv64::GP, 0x80030000);
122
    let first = check(&mut e, entry, 142);
123
    let second = check(&mut e, entry, 143);
124
    emit::loadImm(&mut e, rv64::GP, 0x80030800);
125
    let other = check(&mut e, entry, 142);
126
    emit::loadImm(&mut e, rv64::GP, 0x80030000);
127
    let resumed = check(&mut e, entry, 144);
128
    finish(&mut e, 0x5555);
129
    let failure = e.codeLen;
130
    finish(&mut e, 0x13333);
131
    for index in &[first, second, other, resumed] {
132
        emit::patch(&mut e, index, encode::bne(rv64::A0, rv64::T0, (failure - index) as i32 * 4));
133
    }
134
    for i in 0..TEXT.len {
135
        set TEXT[i] = encode::nop();
136
    }
137
    assert e.codeLen <= 1024;
138
    let codeEmitter: 'code = &e in {
139
        for word, i in emit::getCode 'code (codeEmitter) {
140
            set TEXT[i] = word;
141
        }
142
    }
143
    for package, i in &catalog[..] {
144
        assert package.code.len <= 1024;
145
        for word, j in package.code {
146
            set TEXT[1024 + i * 1024 + j] = word;
147
        }
148
    }
149
    let header = try! image::header(image::Layout {
150
        entry: 0x80010000,
151
        code: image::Segment { address: 0x80010000, initialized: 16384, memory: 16384 },
152
        roData: image::Segment { address: 0, initialized: 0, memory: 0 },
153
        rwData: image::Segment { address: 0x80020000, initialized: STATE.len, memory: STATE.len },
154
    });
155
    let fd = unix::openOpts(env.args[3], unix::OpenFlags(*unix::O_WRONLY | *unix::O_CREAT | *unix::O_TRUNC), 420);
156
    assert fd >= 0;
157
    let written = unix::writeAll(fd, &header[..]) and unix::writeAll(fd, @sliceOf(&TEXT[0] as *u8, 16384)) and unix::writeAll(fd, &STATE[..]);
158
    let closed = unix::close(fd) == 0;
159
    assert written and closed;
160
    return 0;
161
}