1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// 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..

use crate::enclave::state::{self, State};
use crate::enclave::{atexit, parse};
use crate::tcs::ThreadControl;
use core::sync::atomic::AtomicBool;
use sgx_types::error::SgxResult;

pub static UNINIT_FLAG: AtomicBool = AtomicBool::new(false);

pub fn dtors() -> SgxResult {
    if let Some(uninit_array) = parse::uninit_array()? {
        let fn_array = uninit_array.get_array();
        for f in fn_array {
            f.get_fn()();
        }
    }
    Ok(())
}

#[inline]
pub fn at_exit_cleaup() {
    atexit::cleanup();
}

pub fn rtuninit(tc: ThreadControl) -> SgxResult {
    use crate::call;
    use crate::tcs;
    use core::ptr;
    use core::sync::atomic::Ordering;
    use sgx_types::error::SgxStatus;

    if UNINIT_FLAG.load(Ordering::SeqCst) {
        state::set_state(State::Crashed);
        return Ok(());
    }

    let current = tcs::current();
    let tcs = tc.tcs();
    assert!(ptr::eq(current.tcs(), tcs));

    cfg_if! {
        if #[cfg(feature = "sim")] {
            let is_legal = tc.is_init();
        } else if #[cfg(feature = "hyper")] {
            let is_legal = tc.is_init();
        } else {
            use crate::feature::SysFeatures;
            use crate::edmm::{self, layout::LayoutTable};

            let is_legal = if SysFeatures::get().is_edmm() {
                tc.is_utility() || !LayoutTable::new().is_dyn_tcs_exist()
            } else {
                tc.is_init()
            };
        }
    }
    if !is_legal {
        state::set_state(State::Crashed);
        bail!(SgxStatus::Unexpected);
    }

    UNINIT_FLAG.store(true, Ordering::SeqCst);

    #[cfg(not(any(feature = "sim", feature = "hyper")))]
    {
        if SysFeatures::get().is_edmm() && edmm::tcs::accept_trim_tcs(tcs).is_err() {
            state::set_state(State::Crashed);
            bail!(SgxStatus::Unexpected);
        }
    }

    let guard = call::FIRST_ECALL.lock();
    if call::FIRST_ECALL.is_completed() {
        at_exit_cleaup();
        let _ = dtors();
    }
    drop(guard);

    state::set_state(State::Crashed);
    Ok(())
}

#[allow(unused_variables)]
pub fn global_exit(tc: ThreadControl) -> SgxResult {
    extern "C" {
        fn global_exit_ecall();
    }
    unsafe { global_exit_ecall() }

    cfg_if! {
        if #[cfg(feature = "sim")] {
            rtuninit(tc)
        } else if #[cfg(feature = "hyper")] {
            rtuninit(tc)
        } else {
            use crate::feature::SysFeatures;
            if !SysFeatures::get().is_edmm() {
                rtuninit(tc)
            } else {
                Ok(())
            }
        }
    }
}