1#![allow(
2 stable_features,
3 internal_features,
4 clippy::bad_bit_mask,
5 clippy::missing_safety_doc
6)]
7#![feature(
8 asm_experimental_arch,
9 alloc_error_handler,
10 global_asm,
11 const_loop,
12 const_if_match,
13 core_intrinsics,
14 c_variadic,
15 lang_items,
16 rustc_attrs
17)]
18#![feature(std_internals, panic_info_message, panic_internals, c_unwind)]
20#![cfg_attr(not(feature = "stub-only"), feature(panic_unwind))]
21#![cfg_attr(feature = "std", feature(psp_std))]
22#![allow(incomplete_features)]
24#![cfg_attr(not(feature = "std"), no_std)]
25
26#[macro_use]
27extern crate paste;
28#[cfg(not(feature = "stub-only"))]
29extern crate alloc;
30#[cfg(not(feature = "stub-only"))]
31extern crate panic_unwind;
32
33#[macro_use]
34#[doc(hidden)]
35#[cfg(not(feature = "stub-only"))]
36pub mod debug;
37
38#[macro_use]
39mod vfpu;
40mod eabi;
41pub mod math;
42pub mod sys;
43#[cfg(not(feature = "stub-only"))]
44pub mod test_runner;
45#[cfg(not(feature = "stub-only"))]
46pub mod vram_alloc;
47
48#[cfg(not(feature = "stub-only"))]
49mod alloc_impl;
50#[cfg(not(feature = "stub-only"))]
51pub mod panic;
52
53#[cfg(not(feature = "stub-only"))]
54mod screenshot;
55#[cfg(not(feature = "stub-only"))]
56pub use screenshot::*;
57
58#[cfg(not(feature = "stub-only"))]
59mod benchmark;
60#[cfg(not(feature = "stub-only"))]
61pub use benchmark::*;
62
63#[cfg(not(feature = "stub-only"))]
64mod constants;
65#[cfg(not(feature = "stub-only"))]
66pub use constants::*;
67
68#[doc(hidden)]
69pub use unstringify::unstringify;
70
71#[cfg(not(feature = "std"))]
72#[cfg(feature = "stub-only")]
73#[panic_handler]
74fn panic(_: &core::panic::PanicInfo) -> ! {
75 loop {
76 core::hint::spin_loop()
77 }
78}
79
80#[cfg(not(test))]
81#[cfg_attr(not(bootstrap), rustc_std_internal_symbol)]
82extern "C" fn __rust_foreign_exception() -> ! {
83 loop {
84 core::hint::spin_loop()
85 }
86}
87
88#[cfg(feature = "std")]
89pub use std::panic::catch_unwind;
90
91#[cfg(all(not(feature = "std"), not(feature = "stub-only")))]
92pub use panic::catch_unwind;
93
94#[cfg(feature = "embedded-graphics")]
95pub mod embedded_graphics;
96
97#[repr(align(16))]
98#[derive(Copy, Clone)]
99pub struct Align16<T>(pub T);
100
101#[cfg(all(target_os = "psp", not(feature = "stub-only")))]
102core::arch::global_asm!(
103 r#"
104 .section .lib.ent.top, "a", @progbits
105 .align 2
106 .word 0
107 .global __lib_ent_top
108 __lib_ent_top:
109 .section .lib.ent.btm, "a", @progbits
110 .align 2
111 .global __lib_ent_bottom
112 __lib_ent_bottom:
113 .word 0
114
115 .section .lib.stub.top, "a", @progbits
116 .align 2
117 .word 0
118 .global __lib_stub_top
119 __lib_stub_top:
120 .section .lib.stub.btm, "a", @progbits
121 .align 2
122 .global __lib_stub_bottom
123 __lib_stub_bottom:
124 .word 0
125 "#
126);
127
128#[cfg(feature = "std")]
129extern "C" {
130 #[link_name = "main"]
131 #[doc(hidden)]
132 pub fn c_main(argc: isize, argv: *const *const u8) -> isize;
133}
134
135#[cfg(feature = "std")]
138#[doc(hidden)]
139#[macro_export]
140macro_rules! _start {
141 ($_:expr, $argc:expr, $argv:expr) => {
142 unsafe { $crate::c_main($argc as _, $argv as _) as _ }
143 };
144}
145#[cfg(not(feature = "std"))]
146#[doc(hidden)]
147#[macro_export]
148macro_rules! _start {
149 ($psp_main:expr, $argc:expr, $argv:expr) => {{
150 unsafe fn init_cwd(arg0: *mut u8) {
151 let mut len = 0;
152 while *arg0.add(len) != 0 {
153 len += 1;
154 }
155
156 while len > 0 && *arg0.add(len - 1) != b'/' {
158 len -= 1;
159 }
160
161 if len > 0 {
162 let tmp = *arg0.add(len);
163 *arg0.add(len) = 0;
164 $crate::sys::sceIoChdir(arg0 as *const u8);
165 *arg0.add(len) = tmp;
166 }
167 }
168
169 if $argc > 0 {
170 unsafe { init_cwd($argv as *mut u8) };
171 }
172
173 let _ = $crate::catch_unwind($psp_main);
175
176 0
177 }};
178}
179
180#[macro_export]
185macro_rules! module {
186 ($name:expr, $version_major:expr, $version_minor: expr) => {
187 #[doc(hidden)]
188 mod __psp_module {
189 #[no_mangle]
190 #[link_section = ".rodata.sceModuleInfo"]
191 #[used]
192 static MODULE_INFO: $crate::Align16<$crate::sys::SceModuleInfo> =
193 $crate::Align16($crate::sys::SceModuleInfo {
194 mod_attribute: 0,
195 mod_version: [$version_major, $version_minor],
196 mod_name: $crate::sys::SceModuleInfo::name($name),
197 terminal: 0,
198 gp_value: unsafe { &_gp },
199 stub_top: unsafe { &__lib_stub_top },
200 stub_end: unsafe { &__lib_stub_bottom },
201 ent_top: unsafe { &__lib_ent_top },
202 ent_end: unsafe { &__lib_ent_bottom },
203 });
204
205 extern "C" {
206 static _gp: u8;
207 static __lib_ent_bottom: u8;
208 static __lib_ent_top: u8;
209 static __lib_stub_bottom: u8;
210 static __lib_stub_top: u8;
211 }
212
213 #[no_mangle]
214 #[link_section = ".lib.ent"]
215 #[used]
216 static LIB_ENT: $crate::sys::SceLibraryEntry = $crate::sys::SceLibraryEntry {
217 name: core::ptr::null(),
219 version: ($version_major, $version_minor),
220 attribute: $crate::sys::SceLibAttr::SCE_LIB_IS_SYSLIB,
221 entry_len: 4,
222 var_count: 1,
223 func_count: 1,
224 entry_table: &LIB_ENT_TABLE,
225 };
226
227 #[no_mangle]
228 #[link_section = ".rodata.sceResident"]
229 #[used]
230 static LIB_ENT_TABLE: $crate::sys::SceLibraryEntryTable =
231 $crate::sys::SceLibraryEntryTable {
232 module_start_nid: 0xd632acdb, module_info_nid: 0xf01d73a7, module_start: module_start,
235 module_info: &MODULE_INFO.0,
236 };
237
238 use core::ffi::c_void;
239
240 #[no_mangle]
241 extern "C" fn module_start(argc_bytes: usize, argv: *mut c_void) -> isize {
242 extern "C" fn main_thread(argc: usize, argv: *mut c_void) -> i32 {
243 $crate::_start!(super::psp_main, argc, argv)
244 }
245
246 unsafe {
247 let id = $crate::sys::sceKernelCreateThread(
248 b"main_thread\0".as_ptr(),
249 main_thread,
250 32,
252 256 * 1024,
254 $crate::sys::ThreadAttributes::USER | $crate::sys::ThreadAttributes::VFPU,
255 core::ptr::null_mut(),
256 );
257
258 $crate::sys::sceKernelStartThread(id, argc_bytes, argv);
259 }
260
261 0
262 }
263 }
264 };
265}
266
267pub fn enable_home_button() {
272 use core::{ffi::c_void, ptr};
273 use sys::ThreadAttributes;
274
275 unsafe {
276 unsafe extern "C" fn exit_thread(_args: usize, _argp: *mut c_void) -> i32 {
277 unsafe extern "C" fn exit_callback(_arg1: i32, _arg2: i32, _arg: *mut c_void) -> i32 {
278 sys::sceKernelExitGame();
279 0
280 }
281
282 let id = sys::sceKernelCreateCallback(
283 &b"exit_callback\0"[0],
284 exit_callback,
285 ptr::null_mut(),
286 );
287
288 sys::sceKernelRegisterExitCallback(id);
289 sys::sceKernelSleepThreadCB();
290
291 0
292 }
293
294 let id = sys::sceKernelCreateThread(
296 &b"exit_thread\0"[0],
297 exit_thread,
298 32,
299 0x1000,
300 ThreadAttributes::empty(),
301 ptr::null_mut(),
302 );
303
304 sys::sceKernelStartThread(id, 0, ptr::null_mut());
305 }
306}