-
-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Add new Tier-3 target: powerpc64-sony-ps3
#162072
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() | ||
| }, | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Gelbpunkt are you familiar with this? Seems like something to note for the proposed ppc bare metal targets
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For further clarification:
Note: normally
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, I am. LLD does not support ELFv1. This is one of the reasons I quoted for making Linux already prefers ELFv2 on powerpc64, but the proposed bare metal target was for ELFv1, which is weird 🤷♀️ |
||
|
|
||
| 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. | ||
Uh oh!
There was an error while loading. Please reload this page.