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
use crate::result::*;
use crate::svc;
use crate::mem::alloc;
use crate::rrt0;
use crate::ipc::sf;
use crate::service;
use crate::service::fatal;
use crate::service::fatal::IService;
use core::mem;
bit_enum! {
AbortLevel (u32) {
NeedsHeapAllocation = bit!(31),
FatalThrow = bit!(0) | Self::NeedsHeapAllocation().get(),
Panic = bit!(2) | Self::NeedsHeapAllocation().get(),
ProcessExit = bit!(3),
SvcBreak = bit!(4)
}
}
impl AbortLevel {
const LEVEL_ORDER: &'static [AbortLevel] = &[AbortLevel::FatalThrow(), AbortLevel::Panic(), AbortLevel::ProcessExit(), AbortLevel::SvcBreak()];
#[inline]
pub fn get_next_level(self) -> Option<Self> {
for i in 0..Self::LEVEL_ORDER.len() {
if Self::LEVEL_ORDER[i] == self {
let next_i = i + 1;
if next_i < Self::LEVEL_ORDER.len() {
return Some(Self::LEVEL_ORDER[next_i]);
}
}
}
None
}
}
fn do_abort(level: AbortLevel, rc: ResultCode) {
if level.contains(AbortLevel::NeedsHeapAllocation()) && !alloc::is_enabled() {
return;
}
if level == AbortLevel::FatalThrow() {
match service::new_service_object::<fatal::Service>() {
Ok(fatal) => {
let _ = fatal.get().throw_fatal_with_policy(rc, fatal::FatalPolicy::ErrorScreen, sf::ProcessId::new());
},
_ => {}
};
}
else if level == AbortLevel::Panic() {
let res: Result<()> = Err(rc);
res.unwrap();
}
else if level == AbortLevel::ProcessExit() {
rrt0::exit(rc);
}
else if level == AbortLevel::SvcBreak() {
svc::break_(svc::BreakReason::Panic, &rc as *const _ as *const u8, mem::size_of_val(&rc));
}
}
pub fn abort(desired_level: AbortLevel, rc: ResultCode) -> ! {
let mut current_level = desired_level;
loop {
do_abort(current_level, rc);
if let Some(next_level) = current_level.get_next_level() {
current_level = next_level;
}
else {
unreachable!();
}
}
}