diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a1c8fd304cd94..0f192379ce7fc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1615,6 +1615,7 @@ supported_targets! { ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi), ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf), + ("powerpc64-sony-ps3", powerpc64_sony_ps3), ("mipsel-sony-psp", mipsel_sony_psp), ("mipsel-sony-psx", mipsel_sony_psx), ("mipsel-unknown-none", mipsel_unknown_none), @@ -1862,6 +1863,7 @@ crate::target_spec_enum! { Nto = "nto", NuttX = "nuttx", OpenBsd = "openbsd", + Ps3 = "ps3", Psp = "psp", Psx = "psx", Qnx = "qnx", diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs b/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs new file mode 100644 index 0000000000000..41c8b3b206395 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs @@ -0,0 +1,107 @@ +use crate::spec::{ + Arch, Cc, CfgAbi, CodeModel, Endian, FramePointer, LinkerFlavor, Lld, LlvmAbi, Os, + PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, +}; + +pub(crate) fn target() -> Target { + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::No, Lld::No), + &[ + // We strictly need ELFv1 PPC64. + "-m", + "elf64ppc", + // PS3 LV2 reserves the first 64KB page for unmapped memory protection. + "--image-base=0x10000", + // Should be default, but relying on automatic behavior appears to be brittle. + "-e", + "_start", + // CellOS expects .rodata to be merged into the executable Text segment (RX) + // so there are only 2 loadable segments (RX and RW) + "--no-rosegment", + // CellOS uses 64 KB memory pages. Without this flag, `mold` might align data segments to 4 KB boundaries. + "-z", + "separate-loadable-segments", + // Prevents mold from creating a `PT_GNU_RELRO` segment that GameOS does not support. + "-z", + "norelro", + // CellOS's loader doesn't behave like `ld`. PRXs are stubbed in the binary already. + "-Bstatic", + // The following are segments that might never be referenced by the code, + // but are expected to exist by the PS3's loader. + "-u", + "sys_process_param", + "-u", + "sys_proc_prx_param", + "--undefined-glob=*_prx_header", + "--undefined-glob=*_fnid_table", + "--undefined-glob=*_name", + "--undefined-glob=*_fstub_table", + ], + ); + + Target { + // LLVM will default to a compatible ELF backend. + llvm_target: "powerpc64-sony-ps3".into(), + + metadata: TargetMetadata { + description: Some("PowerPC64 (big endian) Sony PlayStation 3 (PS3)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + + // We declare pointers to be 64-bit as the PPU _is_ a 64-bit core. + // However, for all real usage the OS limits us to **32-bit pointers**. + // SDKs should therefore take this into account, specifically when handling syscalls. + pointer_width: 64, + + data_layout: "E-m:e-Fi64-i64:64-i128:128-n32:64".into(), + arch: Arch::PowerPC64, + + options: TargetOptions { + // Base PS3 hardware. + vendor: "sony".into(), + endian: Endian::Big, + os: Os::Ps3, + cfg_abi: CfgAbi::ElfV1, + llvm_abiname: LlvmAbi::ElfV1, + features: "+altivec".into(), + + // CellOS requiring ELFv1 makes LLVM's `lld` incompatible. + // See: + // - [rust-lang/rust#85589](https://github.com/rust-lang/rust/issues/85589) + // - [llvm/llvm-project#27630](https://github.com/llvm/llvm-project/issues/27630) + linker: Some("mold".into()), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No), + + // CellOS _is_ case-sensitive, but the PS3's binaries vary + // in casing depending on whether they are games in `/dev_hdd0` + // or system binaries (such as PRX files). + // + // All games use the .ELF (uppercase) suffix, and Sony's own + // documentation and tools expect user app binaries to be uppercase. + exe_suffix: ".ELF".into(), + + // This limits us to 64KB of ToC, but yields smaller binaries and less assembly. + // Only becomes a problem for binaries with thousands of dependencies. + code_model: Some(CodeModel::Small), + // Prevents LLVM from emitting modern linker relaxation relocations. + relax_elf_relocations: false, + // CellOS main executables (`EBOOT.ELF`) **must be static executables** (ET_EXEC). + relocation_model: RelocModel::Static, + + // Locking defaults against future changes. + c_int_width: 32, + executables: true, + frame_pointer: FramePointer::MayOmit, + // Change this to `true` for developing kernel-mode applications. + // This target defaults to user-mode, and the kernel already handles + // this for us, so keeping it off is a performance gain. + disable_redzone: false, + + panic_strategy: PanicStrategy::Abort, + pre_link_args, + ..Default::default() + }, + } +} diff --git a/library/compiler-builtins/crates/symcheck/src/main.rs b/library/compiler-builtins/crates/symcheck/src/main.rs index a88aeed40fb0d..b5d5fecd63cb6 100644 --- a/library/compiler-builtins/crates/symcheck/src/main.rs +++ b/library/compiler-builtins/crates/symcheck/src/main.rs @@ -210,6 +210,7 @@ impl Target { "nto" => Os::Nto, "nuttx" => Os::Nuttx, "openbsd" => Os::OpenBsd, + "ps3" => Os::Ps3, "psp" => Os::Psp, "psx" => Os::Psx, "qurt" => Os::Qurt, @@ -324,6 +325,7 @@ enum Os { Nto, Nuttx, OpenBsd, + Ps3, Psp, Psx, Qurt, diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index b9c79ab0128e9..f15c712c32b91 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -110,6 +110,7 @@ - [powerpc-unknown-linux-gnuspe](platform-support/powerpc-unknown-linux-gnuspe.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [powerpc64-sony-ps3](platform-support/powerpc64-sony-ps3.md) - [powerpc64-unknown-linux-gnuelfv2](platform-support/powerpc64-unknown-linux-gnuelfv2.md) - [powerpc64-unknown-linux-musl](platform-support/powerpc64-unknown-linux-musl.md) - [powerpc64le-unknown-linux-gnu](platform-support/powerpc64le-unknown-linux-gnu.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7518ee9fabbbc..b34f4dd5b8874 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -388,6 +388,7 @@ target | std | host | notes [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) +[`powerpc64-sony-ps3`](platform-support/powerpc64-sony-ps3.md) | * | | PowerPC64 (BE) Sony PlayStation 3 (PS3) [`powerpc64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64 FreeBSD (ELFv2) [`powerpc64-unknown-linux-gnuelfv2`](platform-support/powerpc64-unknown-linux-gnuelfv2.md) | ✓ | ✓ | PPC64 Linux (ELFv2 ABI, kernel 3.2, glibc 2.17) [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 diff --git a/src/doc/rustc/src/platform-support/powerpc64-sony-ps3.md b/src/doc/rustc/src/platform-support/powerpc64-sony-ps3.md new file mode 100644 index 0000000000000..0c0c4327c355e --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc64-sony-ps3.md @@ -0,0 +1,93 @@ +# `powerpc64-sony-ps3` + +**Tier: 3** + +Target for the Sony PlayStation 3 (shortened to "PS3"), for the PowerPC Processor Element (PPU) of the [Cell Broadband Engine Architecture (CBEA)](https://ieeexplore.ieee.org/document/5388675). + +## Target maintainers + +- [@ZephyrCodesStuff](https://github.com/ZephyrCodesStuff) (Primary developer and maintainer) +- [@RipleyTom](https://github.com/RipleyTom) (Fallback maintainer) + +## Requirements + +The target is a **big-endian PowerPC64 ELFv1** platform (the Cell Broadband Engine's PPE), and intended only for use on Sony PlayStation 3 systems, under the official operating system, "CellOS". + +The linker must support **Big-Endian PowerPC64 ELFv1**: the recommended and tested linker is [mold](https://github.com/rui314/mold). LLVM's `lld` does not correctly handle ELFv1 call relocations in freestanding `no_std` environments, making it incompatible. (See: [rust-lang/rust#85589](https://github.com/rust-lang/rust/issues/85589), [llvm/llvm-project#27630](https://github.com/llvm/llvm-project/issues/27630)) + +Resulting binaries require additional patching after linking to adhere to the PlayStation 3 operating system, in order to be bootable. An open-source patcher is available [here](https://github.com/ZephyrCodesStuff/rust-ps3/tree/main/moldier). Generally, a patcher must perform the following: + +- Rewrite the ELF OS/ABI to `0x66` (`ELFOSABI_CELLLV2`) +- Strip any GNU/Linux headers +- Add Sony-specific flags, sections (`.sys_proc_param` and `.sys_proc_prx_param`) and headers +- Add "stubs" for Sony SPRX dynamic-link libraries, by adding a section (`.lib.stub`) for CellOS to be able to link them +- Patch OPD function descriptors (in the `.opd` section) + +_**Note**: this list may not be exhaustive for all use cases, but is sufficient for producing a runnable binary. Producing a PRX dynamic library may require more/different steps._ + + +The target _fully supports_: + +- The Rust `core` features +- The Rust `alloc` feature, as the CellOS Lv2 kernel provides virtual memory allocation (`sys_memory_allocate`) on top of which a heap allocator (such as [talc](https://github.com/SFBdragon/talc)) can be implemented. +- AltiVec / VMX SIMD vector extensions (natively supported by LLVM via `+altivec`) + +## Building the target + +If `rustc` is built with this target enabled, no external C cross-compilation toolchain is strictly required to build the compiler host artifacts, but `mold` must be installed on the host system to perform linking. + +Support for using `lld` as a linker is unlikely, until support for ELFv1 is implemented on `lld`. + +## Building Rust programs + +Because this is a Tier 3 target, pre-compiled standard library artifacts (`core`, `alloc`) are not distributed via rustup. Programs must be built using a nightly toolchain with the `rust-src` component and `-Z build-std`. + +A Rust SDK ready for development exists open-sourced [here](https://github.com/Zephyrcodesstuff/rust-ps3) and is licensed `MIT OR Apache-2.0`. + +Configure your project `.cargo/config.toml`: +```toml +[target.powerpc64-sony-ps3] +linker = "mold" +rustflags = [ + "-C", "relocation-model=static", + "-C", "code-model=small", + "-C", "target-feature=+altivec", +] +``` + +**Prerequisites:** + +- A nightly Rust compiler with the `rust-src` component +- The [mold](https://github.com/rui314/mold) linker +- The [moldier](https://github.com/ZephyrCodesStuff/rust-ps3/tree/main/moldier) post-linker tool +- *(Optional)* `make_fself` or `scetool` for converting the output `.ELF` into an encrypted/signed `EBOOT.BIN` for running on real hardware. + +**Build process:** + +```bash +# Compile the binary +cargo +nightly build \ + --target powerpc64-sony-ps3 \ + -Z build-std=core,alloc \ + --release + +# Patch the linked executable +moldier patch target/powerpc64-sony-ps3/release/my_program.ELF + +# (Optional) Sign the binary for official hardware +make_fself "target/powerpc64-sony-ps3/release/my_program.ELF" "target/powerpc64-sony-ps3/release/my_program.BIN" +``` + +## Testing + +The target fully supports running binaries (once they're patched), both on official hardware and on [open-source emulators](https://github.com/rpcs3/rpcs3). + +As official firmware for the system forbids running unsigned code, the system must first be jailbroken in order to run binaries. This is not optional. + +Emulators do not impose any requirement regarding codesigning, thus testing on emulators is straightforward. + +Debugging is fully possible, either via debug firmware APIs on the official hardware, or on emulators via either their integrated debuggers, or a GDB server the emulator provides. + +## Cross-compilation toolchains and C code + +The target fully supports C/C++ code. Any compiler capable of producing binaries for a PowerPC64 big-endian processor can produce code to be embedded into the Rust program. diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 04c54e134b48e..db63dbaa24663 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -685,6 +685,7 @@ fn human_readable_target_os(os: Symbol) -> Option<&'static str> { Nto => "QNX SDP 7.x", NuttX => "NuttX", OpenBsd => "OpenBSD", + Ps3 => "Play Station 3", Psp => "Play Station Portable", Psx => "Play Station 1", Qnx => "QNX SDP 8.0+", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs index 1672e8e7930e3..c314b3f37c04d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs @@ -114,7 +114,7 @@ const KNOWN_ARCH: [&str; 20] = [ const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"]; -const KNOWN_OS: [&str; 20] = [ +const KNOWN_OS: [&str; 21] = [ "cuda", "dragonfly", "emscripten", @@ -128,6 +128,7 @@ const KNOWN_OS: [&str; 20] = [ "netbsd", "none", "openbsd", + "ps3", "psp", "redox", "solaris", diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index 49bced1dd5bd2..beefbdb889940 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -403,6 +403,9 @@ //@ revisions: msp430_none_elf //@ [msp430_none_elf] compile-flags: --target msp430-none-elf //@ [msp430_none_elf] needs-llvm-components: msp430 +//@ revisions: powerpc64_sony_ps3 +//@ [powerpc64_sony_ps3] compile-flags: --target powerpc64-sony-ps3 +//@ [powerpc64_sony_ps3] needs-llvm-components: powerpc //@ revisions: powerpc64_unknown_freebsd //@ [powerpc64_unknown_freebsd] compile-flags: --target powerpc64-unknown-freebsd //@ [powerpc64_unknown_freebsd] needs-llvm-components: powerpc diff --git a/tests/rustdoc-html/doc-cfg/all-targets.rs b/tests/rustdoc-html/doc-cfg/all-targets.rs index d5a8be83bc1d3..aec251878781e 100644 --- a/tests/rustdoc-html/doc-cfg/all-targets.rs +++ b/tests/rustdoc-html/doc-cfg/all-targets.rs @@ -79,11 +79,11 @@ pub fn bar() {} // Emscripten and ESP-IDF and FreeBSD and Fuchsia and GNU/Hurd and Haiku \ // and HelenOS and Hermit and Horizon and illumos and iOS and L4Re and Linux \ // and LynxOS-178 and macOS and Managarm and Motor OS and NetBSD and NuttX \ -// and OpenBSD and Play Station 1 and Play Station Portable and Play Station Vita \ -// and QNX SDP 7.x and QNX SDP 8.0+ and QuRT and Redox OS and RTEMS OS and Solaris and \ -// SOLID ASP3 and TEEOS and Trusty and tvOS and UEFI and VEXos and visionOS \ -// and VxWorks and WASI and watchOS and Windows and Xous and zero knowledge \ -// Virtual Machine only.' +// and OpenBSD and Play Station 1 and Play Station 3 and Play Station Portable \ +// and Play Station Vita and QNX SDP 7.x and QNX SDP 8.0+ and QuRT and Redox OS \ +// and RTEMS OS and Solaris and SOLID ASP3 and TEEOS and Trusty and tvOS and UEFI \ +// and VEXos and visionOS and VxWorks and WASI and watchOS and Windows and Xous \ +// and zero knowledge Virtual Machine only.' #[doc(cfg(all( target_os = "aix", target_os = "amdhsa", @@ -114,6 +114,7 @@ pub fn bar() {} target_os = "qnx", target_os = "nuttx", target_os = "openbsd", + target_os = "ps3", target_os = "psp", target_os = "psx", target_os = "qurt", diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr index 9bf3cef403159..d65562313cb42 100644 --- a/tests/ui/check-cfg/cfg-crate-features.stderr +++ b/tests/ui/check-cfg/cfg-crate-features.stderr @@ -24,7 +24,7 @@ warning: unexpected `cfg` condition value: `does_not_exist` LL | #![cfg(not(target(os = "does_not_exist")))] | ^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, and `solaris` and 15 more + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, and `rtems` and 16 more = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 395a739b0be72..98404cd495dcf 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -232,7 +232,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -305,7 +305,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 31 warnings emitted