To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

aot.rs 28.6 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
2
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
3
4
5
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
9
10
11
12
13
14
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15
16
extern crate time;

qinsoon's avatar
qinsoon committed
17
use linkutils::*;
qinsoon's avatar
qinsoon committed
18
19
use ast::ir::MuName;
use runtime;
qinsoon's avatar
qinsoon committed
20
use vm::VM;
qinsoon's avatar
qinsoon committed
21
use compiler::backend;
qinsoon's avatar
qinsoon committed
22

qinsoon's avatar
qinsoon committed
23
24
25
use std::path::PathBuf;
use std::process::Command;

qinsoon's avatar
qinsoon committed
26
27
/// links generated code for the given functions, static library of Zebu,
/// and a main function to produce an executable of the given name
28
pub fn link_primordial(funcs: Vec<MuName>, out: &str, vm: &VM) -> PathBuf {
qinsoon's avatar
qinsoon committed
29
30
31
    let emit_dir = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);

    // prepare a list of files that need to be compiled and linked together
32
    let files: Vec<PathBuf> = {
qinsoon's avatar
qinsoon committed
33
34
35
36
37
38
39
40
41
42
43
44
45
        use std::fs;

        let mut ret = vec![];

        // all interested mu funcs
        for func in funcs {
            ret.push(get_path_for_mu_func(func, vm));
        }

        // mu context
        ret.push(get_path_for_mu_context(vm));

        // copy primoridal entry
46
        let source = get_path_under_zebu(runtime::PRIMORDIAL_ENTRY);
qinsoon's avatar
qinsoon committed
47
48
49
50
51
52
53
54
        let dest = {
            let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
            ret.push("main.c");

            ret
        };
        trace!("copying from {:?} to {:?}", source, dest);
        match fs::copy(source.as_path(), dest.as_path()) {
55
            Ok(_) => {}
56
            Err(e) => panic!("failed to copy: {}", e)
qinsoon's avatar
qinsoon committed
57
58
59
60
61
62
        }

        // include the primordial C main
        ret.push(dest);

        // include mu static lib
63
64
65
66
67
68
69
        if vm.vm_options.flag_link_staticly {
            ret.push(get_path_under_zebu(if cfg!(debug_assertions) {
                "target/debug/libmu.a"
            } else {
                "target/release/libmu.a"
            }));
        }
qinsoon's avatar
qinsoon committed
70
71
72
73
74
75
76

        ret
    };

    let mut out_path = emit_dir.clone();
    out_path.push(out);

77
    link_executable_internal(
78
        !vm.vm_options.flag_link_staticly,
79
80
81
        files,
        &vm.vm_options.flag_bootimage_external_lib,
        &vm.vm_options.flag_bootimage_external_libpath,
82
        out_path
83
    )
qinsoon's avatar
qinsoon committed
84
85
}

86
87
88
89
/// links generated code for the given test's functions, static library of Zebu,
/// and a main function to produce an executable of the given name
pub fn link_test_primordial(funcs: Vec<MuName>, out: &str, vm: &VM) -> PathBuf {
    let emit_dir = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
90

91
92
93
    // prepare a list of files that need to be compiled and linked together
    let files: Vec<PathBuf> = {
        use std::fs;
94

95
        let mut ret = vec![];
96

97
98
99
100
        // all interested mu funcs
        for func in funcs {
            ret.push(get_path_for_mu_func(func, vm));
        }
101

102
103
        // mu context
        ret.push(get_path_for_mu_context(vm));
104

105
106
107
108
109
        // copy primoridal entry
        let source = get_path_under_zebu(runtime::PRIMORDIAL_ENTRY);
        let dest = {
            let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
            ret.push("main_test.c");
110

111
112
113
114
115
116
117
            ret
        };
        trace!("copying from {:?} to {:?}", source, dest);
        match fs::copy(source.as_path(), dest.as_path()) {
            Ok(_) => {}
            Err(e) => panic!("failed to copy: {}", e)
        }
118

119
120
        // include the primordial C main
        ret.push(dest);
121

122
123
124
125
126
127
128
129
        // include mu static lib
        if vm.vm_options.flag_link_staticly {
            ret.push(get_path_under_zebu(if cfg!(debug_assertions) {
                "target/debug/libmu.a"
            } else {
                "target/release/libmu.a"
            }));
        }
130

131
132
        ret
    };
133

134
135
    let mut out_path = emit_dir.clone();
    out_path.push(out);
136

137
    link_executable_internal(
138
        !vm.vm_options.flag_link_staticly,
139
140
141
142
143
144
145
        files,
        &vm.vm_options.flag_bootimage_external_lib,
        &vm.vm_options.flag_bootimage_external_libpath,
        out_path
    )
}

qinsoon's avatar
qinsoon committed
146
/// invokes the C compiler to link code into an executable
147
fn link_executable_internal(
148
    link_dynamicly: bool,
149
150
151
    files: Vec<PathBuf>,
    lib: &Vec<String>,
    libpath: &Vec<String>,
152
    out: PathBuf
153
) -> PathBuf {
qinsoon's avatar
qinsoon committed
154
155
156
    info!("output as {:?}", out.as_path());

    let mut cc = Command::new(get_c_compiler());
qinsoon's avatar
qinsoon committed
157

158
159
160
161
162
163
    // external libs
    for path in libpath.iter() {
        cc.arg(format!("-L{}", path));
    }
    for l in lib.iter() {
        cc.arg(format!("-l{}", l));
qinsoon's avatar
qinsoon committed
164
165
    }

166
167
168
169
170
171
172
173
174
175
176
177
    if link_dynamicly {
        cc.arg(format!(
            "-L{}",
            get_path_under_zebu(if cfg!(debug_assertions) {
                "target/debug"
            } else {
                "target/release"
            }).to_str()
                .unwrap()
        ));
        cc.arg("-lmu");
    }
qinsoon's avatar
qinsoon committed
178
    // dylibs used for linux
qinsoon's avatar
qinsoon committed
179
    if cfg!(target_os = "linux") {
180
181
182
183
        cc.arg("-ldl");
        cc.arg("-lrt");
        cc.arg("-lm");
        cc.arg("-lpthread");
184
        cc.arg("-lz");
185
186
187
188
189
190
191
192
    } else if cfg!(target_os = "macos") {
        cc.arg("-liconv");
        cc.arg("-framework");
        cc.arg("Security");
        cc.arg("-framework");
        cc.arg("CoreFoundation");
        cc.arg("-lz");
        cc.arg("-lSystem");
193
        cc.arg("-lresolv");
194
195
        cc.arg("-lc");
        cc.arg("-lm");
qinsoon's avatar
qinsoon committed
196
    }
qinsoon's avatar
qinsoon committed
197
    // all the source code
198
199
200
201
202
    for file in files {
        info!("link with {:?}", file.as_path());
        cc.arg(file.as_path());
    }

qinsoon's avatar
qinsoon committed
203
    // flag to allow find symbols in the executable
204
    cc.arg("-rdynamic");
qinsoon's avatar
qinsoon committed
205
206

    // specified output
207
208
    cc.arg("-o");
    cc.arg(out.as_os_str());
qinsoon's avatar
qinsoon committed
209

qinsoon's avatar
qinsoon committed
210
211
    // execute and check results
    assert!(exec_cmd(cc).status.success(), "failed to link code");
qinsoon's avatar
qinsoon committed
212
213
214
    out
}

qinsoon's avatar
qinsoon committed
215
216
/// links generated code for the given functions to produce a dynamic
/// library of the given name
217
pub fn link_dylib(funcs: Vec<MuName>, out: &str, vm: &VM) -> PathBuf {
qinsoon's avatar
qinsoon committed
218
219
220
221
222
    link_dylib_with_extra_srcs(funcs, vec![], out, vm)
}

/// links generated code for the given functions with a few external sources
/// to produce a dynamic library of the given name
223
224
225
226
pub fn link_dylib_with_extra_srcs(
    funcs: Vec<MuName>,
    srcs: Vec<String>,
    out: &str,
227
    vm: &VM
228
) -> PathBuf {
qinsoon's avatar
qinsoon committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
    let files = {
        let mut ret = vec![];

        for func in funcs {
            ret.push(get_path_for_mu_func(func, vm));
        }

        for src in srcs {
            ret.push(PathBuf::from(src));
        }

        ret.push(get_path_for_mu_context(vm));

        ret
    };

    let mut out_path = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
    out_path.push(out);

248
249
250
251
    link_dylib_internal(
        files,
        &vm.vm_options.flag_bootimage_external_lib,
        &vm.vm_options.flag_bootimage_external_libpath,
252
        out_path
253
    )
qinsoon's avatar
qinsoon committed
254
255
256
}

/// invokes the C compiler to link code into a dynamic library
257
258
259
260
fn link_dylib_internal(
    files: Vec<PathBuf>,
    lib: &Vec<String>,
    libpath: &Vec<String>,
261
    out: PathBuf
262
263
) -> PathBuf {
    let mut object_files: Vec<PathBuf> = vec![];
qinsoon's avatar
qinsoon committed
264

qinsoon's avatar
qinsoon committed
265
    // compile each single source file
qinsoon's avatar
qinsoon committed
266
    for file in files {
qinsoon's avatar
qinsoon committed
267
        let mut cc = Command::new(get_c_compiler());
qinsoon's avatar
qinsoon committed
268

qinsoon's avatar
qinsoon committed
269
        // output object file
270
        cc.arg("-c");
qinsoon's avatar
qinsoon committed
271
        // position independent code
272
        cc.arg("-fPIC");
qinsoon's avatar
qinsoon committed
273
274
275
276

        let mut out = file.clone();
        out.set_extension("o");

277
278
279
        cc.arg(file.as_os_str());
        cc.arg("-o");
        cc.arg(out.as_os_str());
qinsoon's avatar
qinsoon committed
280
281

        object_files.push(out);
qinsoon's avatar
qinsoon committed
282
        exec_cmd(cc);
283
284
    }

qinsoon's avatar
qinsoon committed
285
286
    // link object files into a dynamic library
    let mut cc = Command::new(get_c_compiler());
287
288
289
290
291
292
293

    // external libs
    for path in libpath.iter() {
        cc.arg(format!("-L{}", path));
    }
    for l in lib.iter() {
        cc.arg(format!("-l{}", l));
qinsoon's avatar
qinsoon committed
294
295
    }

qinsoon's avatar
qinsoon committed
296
297
    // options:
    // shared library
298
    cc.arg("-shared");
qinsoon's avatar
qinsoon committed
299
    // position independent code
300
    cc.arg("-fPIC");
qinsoon's avatar
qinsoon committed
301
    // allow undefined symbol
302
303
    cc.arg("-Wl");
    cc.arg("-undefined");
qinsoon's avatar
qinsoon committed
304
    // allow dynamic lookup symbols
305
    cc.arg("dynamic_lookup");
qinsoon's avatar
qinsoon committed
306
307

    // all object files
qinsoon's avatar
qinsoon committed
308
    for obj in object_files {
309
        cc.arg(obj.as_os_str());
qinsoon's avatar
qinsoon committed
310
    }
311

qinsoon's avatar
qinsoon committed
312
    // output
313
314
    cc.arg("-o");
    cc.arg(out.as_os_str());
qinsoon's avatar
qinsoon committed
315

qinsoon's avatar
qinsoon committed
316
    exec_cmd(cc);
qinsoon's avatar
qinsoon committed
317
318
319
320

    out
}

qinsoon's avatar
qinsoon committed
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/// builds a bundle (that contains a function), compiles it,
/// links and loads it as a dynamic library
/// This function is used to test compiler.
//  TODO: should think about using make_boot_image() instead of this adhoc code (Issue #52)
pub fn compile_fnc<'a>(fnc_name: &'static str, build_fnc: &'a Fn() -> VM) -> ll::Library {
    VM::start_logging_trace();

    let vm = Arc::new(build_fnc());
    let compiler = Compiler::new(CompilerPolicy::default(), &vm);
    let func_id = vm.id_of(fnc_name);
    {
        let funcs = vm.funcs().read().unwrap();
        let func = match funcs.get(&func_id) {
            Some(func) => func.read().unwrap(),
335
            None => panic!("cannot find function {}", fnc_name)
qinsoon's avatar
qinsoon committed
336
337
338
339
        };

        let cur_ver = match func.cur_ver {
            Some(v) => v,
340
341
342
343
344
345
            None => {
                panic!(
                    "function {} does not have a defined current version",
                    fnc_name
                )
            }
qinsoon's avatar
qinsoon committed
346
347
348
349
350
        };

        let func_vers = vm.func_vers().read().unwrap();
        let mut func_ver = match func_vers.get(&cur_ver) {
            Some(fv) => fv.write().unwrap(),
351
            None => panic!("cannot find function version {}", cur_ver)
qinsoon's avatar
qinsoon committed
352
353
354
355
356
357
358
359
360
361
362
363
364
        };
        compiler.compile(&mut func_ver);
    }
    backend::emit_context(&vm);
    let libname = &get_dylib_name(fnc_name);
    let dylib = aot::link_dylib(vec![Mu(fnc_name)], libname, &vm);
    ll::Library::new(dylib.as_os_str()).unwrap()
}

/// builds a bundle (that contains several functions), compiles them,
/// links and loads it as a dynamic library
/// This function is used to test compiler.
//  TODO: should think about using make_boot_image() instead of this adhoc code (Issue #52)
365
366
367
pub fn compile_fncs<'a>(
    entry: &'static str,
    fnc_names: Vec<&'static str>,
368
    build_fnc: &'a Fn() -> VM
369
) -> ll::Library {
qinsoon's avatar
qinsoon committed
370
371
372
373
374
375
376
377
378
379
    VM::start_logging_trace();

    let vm = Arc::new(build_fnc());
    let compiler = Compiler::new(CompilerPolicy::default(), &vm);

    for func in fnc_names.iter() {
        let func_id = vm.id_of(func);
        let funcs = vm.funcs().read().unwrap();
        let func = funcs.get(&func_id).unwrap().read().unwrap();
        let func_vers = vm.func_vers().read().unwrap();
380
381
382
383
384
        let mut func_ver = func_vers
            .get(&func.cur_ver.unwrap())
            .unwrap()
            .write()
            .unwrap();
qinsoon's avatar
qinsoon committed
385
386
387
388
389
390
391
392
393
394
395
        compiler.compile(&mut func_ver);
    }

    backend::emit_context(&vm);

    let libname = &get_dylib_name(entry);
    let dylib = aot::link_dylib(fnc_names.iter().map(|x| Mu(x)).collect(), libname, &vm);
    ll::Library::new(dylib.as_os_str()).unwrap()
}

/// gets the path for the generated code of a Mu function
396
fn get_path_for_mu_func(f: MuName, vm: &VM) -> PathBuf {
qinsoon's avatar
qinsoon committed
397
    let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
398
    ret.push((*f).clone() + ".S");
qinsoon's avatar
qinsoon committed
399
400
401
402

    ret
}

qinsoon's avatar
qinsoon committed
403
/// gets the path for generated Mu context (persisted VM/heap)
404
fn get_path_for_mu_context(vm: &VM) -> PathBuf {
qinsoon's avatar
qinsoon committed
405
    let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
qinsoon's avatar
qinsoon committed
406
407
    ret.push(backend::AOT_EMIT_CONTEXT_FILE);
    ret
408
}
409
410

#[cfg(not(feature = "sel4-rumprun"))]
411
412
413
pub fn run_test(vm: &VM, test_name: &str, tester_name: &str) {
    let output_name = test_name.to_string() + "_" + tester_name;
    let executable = link_test_primordial(
414
415
416
417
        vec![
            Arc::new(test_name.to_string()),
            Arc::new(tester_name.to_string()),
        ],
418
419
420
        output_name.as_str(),
        vm
    );
421
422
423
424
    self::super::exec_path(executable);
}

#[cfg(feature = "sel4-rumprun")]
425
426
pub fn run_test(vm: &VM, test_name: &str, tester_name: &str) {

427
    use std::fs::File;
428

429
430
431
432
433
434
435
436
    //  emit/add.s
    let test_asm_file = "emit/".to_string() + test_name + ".S";
    //  emit/add_test1.s
    let tester_asm_file = "emit/".to_string() + tester_name + ".S";
    //  emit/context.s
    let context_asm_file = "emit/".to_string() + "context.S";
    //  emit/mu_sym_table.s
    let mu_sym_table_asm_file = "emit/".to_string() + "mu_sym_table.S";
437

438
439
440
441
442
443
444
    // clean the destination first
    let destination_prefix = "../rumprun-sel4/apps/zebu_rt/src/emit/";
    let output = Command::new("rm")
        .arg("-R")
        .arg(destination_prefix)
        .output()
        .expect("failed to RM dest emit");
445

446
    assert!(output.status.success());
447

448
449
450
451
452
    //  recreate the emit folder, deleted by the previous command
    let output = Command::new("mkdir")
        .arg(destination_prefix)
        .output()
        .expect("failed to RM dest emit");
453

454
    assert!(output.status.success());
455
456


457
458
459
    // above file will be pasted in \
    //  rumprun-sel4/apps/zebu_rt/src + the above Strings
    let destination_prefix = "../rumprun-sel4/apps/zebu_rt/src/";
460

461
462
463
464
    let dest_test_asm_file = destination_prefix.to_string() + &test_asm_file;
    let dest_tester_asm_file = destination_prefix.to_string() + &tester_asm_file;
    let dest_context_asm_file = destination_prefix.to_string() + &context_asm_file;
    let dest_mu_sym_table_asm_file = destination_prefix.to_string() + &mu_sym_table_asm_file;
465

466
467
468
469
470
    /*
        The following 4 commands, copy 4 asm source files to \
        the proper location of filesystem for sel4-rumprun runtime
        This is currently src/emit
    */
471

472
473
474
475
476
    let output = Command::new("cp")
        .arg(&test_asm_file)
        .arg(&dest_test_asm_file)
        .output()
        .expect("failed to copy test_asm_file");
477

478
    assert!(output.status.success());
479

480
481
482
483
484
    let output = Command::new("cp")
        .arg(&tester_asm_file)
        .arg(&dest_tester_asm_file)
        .output()
        .expect("failed to copy tester_asm_file");
485

486
    assert!(output.status.success());
487

488
489
490
491
492
    let output = Command::new("cp")
        .arg(&context_asm_file)
        .arg(&dest_context_asm_file)
        .output()
        .expect("failed to copy context_asm_file");
493

494
    assert!(output.status.success());
495

496
497
498
499
500
    let output = Command::new("cp")
        .arg(&mu_sym_table_asm_file)
        .arg(&dest_mu_sym_table_asm_file)
        .output()
        .expect("failed to copy dest_mu_sym_table_asm_file");
501

502
    assert!(output.status.success());
503
504


505
506
507
508
    /*
        Everything is ready for our sel4-rumprun Zebu runtime
        to start building the final test executable(s)
    */
509

510
511
    use std::os::unix::io::FromRawFd;
    use std::os::unix::io::AsRawFd;
512
513


514
515
516
517
    let output = Command::new("rm")
        .arg("outputs.txt")
        .output()
        .expect("failed to change directory2");
518

519
    let mut outputs_file = File::create("outputs.txt").unwrap();
520

521
    let rawfd = outputs_file.as_raw_fd();
522
    //    let rawfd = unsafe { File::from_raw_fd(rawfd) };
523
    let rawfd = unsafe { Stdio::from_raw_fd(rawfd) };
524

525
526
527
528
529
    let output = Command::new("bash")
        .arg("build_for_sel4_rumprun.sh")
        .stdout(Stdio::inherit())
        .output()
        .expect("failed to Build");
530

531
532
533
    println!("****************************************");
    println!("Build Output -{:?}-", output);
    println!("****************************************");
534

535
    assert!(output.status.success());
536

537
538
    // First create a child process which runs qemu for testing
    // Then, create a watchdog to check if test is finished
539

540
541
542
543
544
545
546
547
548
549
550
551
552
    let mut tester_proc = Command::new("qemu-system-x86_64")
        .arg("-nographic")
        .arg("-m")
        .arg("512")
        .arg("-kernel")
        .arg("../rumprun-sel4/images/kernel-x86_64-pc99")
        .arg("-initrd")
        .arg("../rumprun-sel4/images/roottask-image-x86_64-pc99")
        .arg("-cpu")
        .arg("Haswell")
        .stdout(rawfd)
        .spawn()
        .expect("failed to RUN");
553

554
555
556
    use std::thread;
    use std::io;
    use std::io::prelude::*;
557

558
559
560
    let mut child_proc_finished = 0;
    let mut test_succeeded = 0;
    let mut test_length = 0;
561
562
    let test_length_max = 60; // Maximum allowed length for a test is currently 60 seconds

563
564
565
566
567
568
569
570
571
    // This loop checks the output file to recognize when qemu vm \
    // which is running the test, should be terminated
    while child_proc_finished == 0 {
        thread::sleep_ms(5000);
        test_length += 5;
        {
            let mut results_file = File::open("outputs.txt");
            let mut results_file = match results_file {
                Ok(the_file) => the_file,
572
573
574
                Err(error) => {
                    panic!("Checking outputs file failed with error -{}-", error);
                }
575
576
            };
            let mut file_content = String::new();
577

578
            results_file.read_to_string(&mut file_content);
579

580
581
582
583
            if file_content.contains("bmk_platform_halt@kernel.c:95 All is well in the universe.") {
                child_proc_finished = 1;
                if file_content.contains("@#$%PASSED%$#@") {
                    test_succeeded = 1;
584
585
586
587
                } else if file_content.contains("@#$%FAILED%$#@") {
                    test_succeeded = 0;
                } else {
                    panic!("Invalid test outcome!");
588
                }
589
590
            } else {
                continue;
591
            }
592

593
594
            use std::str::FromStr;
            use std::fs::OpenOptions;
595

596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
            let mut lines = file_content.lines();
            let mut search_finished = 0;
            let mut test_name = String::new();
            while search_finished == 0 {
                let mut current_line = lines.next();
                if current_line == None {
                    panic!("Test name not found in outputs.txt");
                }
                let current_line = current_line.unwrap();
                println!("{}", current_line);
                if current_line.contains("**TEST**") {
                    search_finished = 1;
                    test_name = String::from_str(lines.next().unwrap()).unwrap();
                }
            }
611

612
            //            let mut log_file = File::create("results_log.txt");
613
614
615
616
            let mut log_file = OpenOptions::new()
                .write(true)
                .append(true)
                .open("results_log.txt");
617
618
            let mut log_file = match log_file {
                Ok(the_file) => the_file,
619
620
621
                Err(error) => {
                    panic!("Creating-Opening log file failed with error -{}-", error);
                }
622
            };
623
624
625
626
627
628
629
630
631
632

            log_file
                .write_fmt(format_args!("******************************\n"))
                .unwrap();
            log_file
                .write_fmt(format_args!("Test time : {}\n", time::now_utc().ctime()))
                .unwrap();
            log_file
                .write_fmt(format_args!("Test name : {}\n", test_name))
                .unwrap();
633
            if test_succeeded == 1 {
634
635
636
637
638
639
640
                log_file
                    .write_fmt(format_args!("Test result : PASSED\n"))
                    .unwrap();
            } else {
                log_file
                    .write_fmt(format_args!("Test result : FAILED\n"))
                    .unwrap();
641
            }
642
643
644
            log_file
                .write_fmt(format_args!("******************************"))
                .unwrap();
645
646
647
648
649
650
651
652
653
        }
        println!("+ 5 secs");
        if test_length == test_length_max {
            let output = Command::new("kill")
                .arg("-15")
                .arg("--")
                .arg(tester_proc.id().to_string())
                .output()
                .expect("failed to kill TO");
654

655
            assert!(output.status.success());
656

657
658
659
            panic!("Test Timed Out!");
        }
    }
660

661
662
663
664
665
666
667
    // Terminate the test proc
    let output = Command::new("kill")
        .arg("-15")
        .arg("--")
        .arg(tester_proc.id().to_string())
        .output()
        .expect("failed to kill");
668

669
    assert!(output.status.success());
670

671
672
673
674
    assert!(test_succeeded == 1);
}

#[cfg(not(feature = "sel4-rumprun"))]
675
676
677
678
pub fn run_test_2f(vm: &VM, test_name: &str, dep_name: &str, tester_name: &str) {
    let output_name = test_name.to_string() + "_" + tester_name;
    let executable = link_test_primordial(
        vec![
679
680
681
            Arc::new(dep_name.to_string()),
            Arc::new(test_name.to_string()),
            Arc::new(tester_name.to_string()),
682
683
684
685
        ],
        output_name.as_str(),
        vm
    );
686
687
688
689
    self::super::exec_path(executable);
}

#[cfg(feature = "sel4-rumprun")]
690
691
pub fn run_test_2f(vm: &VM, test_name: &str, dep_name: &str, tester_name: &str) {

692
    use std::fs::File;
693

694
695
696
697
698
699
700
701
702
703
    //  emit/add.s
    let test_asm_file = "emit/".to_string() + test_name + ".S";
    //  emit/add_test1.s
    let tester_asm_file = "emit/".to_string() + tester_name + ".S";
    //  emit/context.s
    let context_asm_file = "emit/".to_string() + "context.S";
    //  emit/mu_sym_table.s
    let mu_sym_table_asm_file = "emit/".to_string() + "mu_sym_table.S";
    //  something like emit/dummy_call.s
    let dep_asm_file = "emit/".to_string() + dep_name + ".S";
704

705
706
707
708
709
710
711
    // clean the destination first
    let destination_prefix = "../rumprun-sel4/apps/zebu_rt/src/emit/";
    let output = Command::new("rm")
        .arg("-R")
        .arg(destination_prefix)
        .output()
        .expect("failed to RM dest emit");
712

713
    assert!(output.status.success());
714

715
716
717
718
719
    //  recreate the emit folder, deleted by the previous command
    let output = Command::new("mkdir")
        .arg(destination_prefix)
        .output()
        .expect("failed to RM dest emit");
720

721
    assert!(output.status.success());
722
723


724
725
726
    // above file will be pasted in \
    //  rumprun-sel4/apps/zebu_rt/src + the above Strings
    let destination_prefix = "../rumprun-sel4/apps/zebu_rt/src/";
727

728
729
730
731
732
    let dest_test_asm_file = destination_prefix.to_string() + &test_asm_file;
    let dest_tester_asm_file = destination_prefix.to_string() + &tester_asm_file;
    let dest_context_asm_file = destination_prefix.to_string() + &context_asm_file;
    let dest_mu_sym_table_asm_file = destination_prefix.to_string() + &mu_sym_table_asm_file;
    let dest_dep_asm_file = destination_prefix.to_string() + &dep_asm_file;
733

734
735
736
737
738
    /*
        The following 4 commands, copy 4 asm source files to \
        the proper location of filesystem for sel4-rumprun runtime
        This is currently src/emit
    */
739

740
741
742
743
744
    let output = Command::new("cp")
        .arg(&test_asm_file)
        .arg(&dest_test_asm_file)
        .output()
        .expect("failed to copy test_asm_file");
745

746
    assert!(output.status.success());
747

748
749
750
751
752
    let output = Command::new("cp")
        .arg(&tester_asm_file)
        .arg(&dest_tester_asm_file)
        .output()
        .expect("failed to copy tester_asm_file");
753

754
    assert!(output.status.success());
755

756
757
758
759
760
    let output = Command::new("cp")
        .arg(&context_asm_file)
        .arg(&dest_context_asm_file)
        .output()
        .expect("failed to copy context_asm_file");
761

762
    assert!(output.status.success());
763

764
765
766
767
768
    let output = Command::new("cp")
        .arg(&mu_sym_table_asm_file)
        .arg(&dest_mu_sym_table_asm_file)
        .output()
        .expect("failed to copy dest_mu_sym_table_asm_file");
769

770
    assert!(output.status.success());
771

772
773
774
775
776
    let output = Command::new("cp")
        .arg(&dep_asm_file)
        .arg(&dest_dep_asm_file)
        .output()
        .expect("failed to copy dep_asm_file");
777

778
    assert!(output.status.success());
779

780
781
782
783
    /*
        Everything is ready for our sel4-rumprun Zebu runtime
        to start building the final test executable(s)
    */
784

785
786
    use std::os::unix::io::FromRawFd;
    use std::os::unix::io::AsRawFd;
787
788


789
790
791
792
    let output = Command::new("rm")
        .arg("outputs.txt")
        .output()
        .expect("failed to change directory2");
793

794
    let mut outputs_file = File::create("outputs.txt").unwrap();
795

796
    let rawfd = outputs_file.as_raw_fd();
797
    //    let rawfd = unsafe { File::from_raw_fd(rawfd) };
798
    let rawfd = unsafe { Stdio::from_raw_fd(rawfd) };
799

800
801
802
803
804
    let output = Command::new("bash")
        .arg("build_for_sel4_rumprun.sh")
        .stdout(Stdio::inherit())
        .output()
        .expect("failed to Build");
805

806
807
808
    println!("****************************************");
    println!("Build Output -{:?}-", output);
    println!("****************************************");
809

810
    assert!(output.status.success());
811

812
813
    // First create a child process which runs qemu for testing
    // Then, create a watchdog to check if test is finished
814

815
816
817
818
819
820
821
822
823
824
825
826
827
    let mut tester_proc = Command::new("qemu-system-x86_64")
        .arg("-nographic")
        .arg("-m")
        .arg("512")
        .arg("-kernel")
        .arg("../rumprun-sel4/images/kernel-x86_64-pc99")
        .arg("-initrd")
        .arg("../rumprun-sel4/images/roottask-image-x86_64-pc99")
        .arg("-cpu")
        .arg("Haswell")
        .stdout(rawfd)
        .spawn()
        .expect("failed to RUN");
828

829
830
831
    use std::thread;
    use std::io;
    use std::io::prelude::*;
832

833
834
835
    let mut child_proc_finished = 0;
    let mut test_succeeded = 0;
    let mut test_length = 0;
836
837
    let test_length_max = 60; // Maximum allowed length for a test is currently 60 seconds

838
839
840
841
842
843
844
845
846
    // This loop checks the output file to recognize when qemu vm \
    // which is running the test, should be terminated
    while child_proc_finished == 0 {
        thread::sleep_ms(5000);
        test_length += 5;
        {
            let mut results_file = File::open("outputs.txt");
            let mut results_file = match results_file {
                Ok(the_file) => the_file,
847
848
849
                Err(error) => {
                    panic!("Checking outputs file failed with error -{}-", error);
                }
850
851
            };
            let mut file_content = String::new();
852

853
            results_file.read_to_string(&mut file_content);
854

855
856
857
858
            if file_content.contains("bmk_platform_halt@kernel.c:95 All is well in the universe.") {
                child_proc_finished = 1;
                if file_content.contains("@#$%PASSED%$#@") {
                    test_succeeded = 1;
859
860
861
862
                } else if file_content.contains("@#$%FAILED%$#@") {
                    test_succeeded = 0;
                } else {
                    panic!("Invalid test outcome!");
863
                }
864
865
            } else {
                continue;
866
            }
867

868
869
            use std::str::FromStr;
            use std::fs::OpenOptions;
870

871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
            let mut lines = file_content.lines();
            let mut search_finished = 0;
            let mut test_name = String::new();
            while search_finished == 0 {
                let mut current_line = lines.next();
                if current_line == None {
                    panic!("Test name not found in outputs.txt");
                }
                let current_line = current_line.unwrap();
                println!("{}", current_line);
                if current_line.contains("**TEST**") {
                    search_finished = 1;
                    test_name = String::from_str(lines.next().unwrap()).unwrap();
                }
            }
886

887
            //            let mut log_file = File::create("results_log.txt");
888
889
890
891
            let mut log_file = OpenOptions::new()
                .write(true)
                .append(true)
                .open("results_log.txt");
892
893
            let mut log_file = match log_file {
                Ok(the_file) => the_file,
894
895
896
                Err(error) => {
                    panic!("Creating-Opening log file failed with error -{}-", error);
                }
897
            };
898
899
900
901
902
903
904
905
906
907

            log_file
                .write_fmt(format_args!("******************************\n"))
                .unwrap();
            log_file
                .write_fmt(format_args!("Test time : {}\n", time::now_utc().ctime()))
                .unwrap();
            log_file
                .write_fmt(format_args!("Test name : {}\n", test_name))
                .unwrap();
908
            if test_succeeded == 1 {
909
910
911
912
913
914
915
                log_file
                    .write_fmt(format_args!("Test result : PASSED\n"))
                    .unwrap();
            } else {
                log_file
                    .write_fmt(format_args!("Test result : FAILED\n"))
                    .unwrap();
916
            }
917
918
919
            log_file
                .write_fmt(format_args!("******************************"))
                .unwrap();
920
921
922
923
924
925
926
927
928
        }
        println!("+ 5 secs");
        if test_length == test_length_max {
            let output = Command::new("kill")
                .arg("-15")
                .arg("--")
                .arg(tester_proc.id().to_string())
                .output()
                .expect("failed to kill TO");
929

930
            assert!(output.status.success());
931

932
933
934
            panic!("Test Timed Out!");
        }
    }
935

936
937
938
939
940
941
942
    // Terminate the test proc
    let output = Command::new("kill")
        .arg("-15")
        .arg("--")
        .arg(tester_proc.id().to_string())
        .output()
        .expect("failed to kill");
943

944
    assert!(output.status.success());
945

946
947
    assert!(test_succeeded == 1);
}