Skip to content

Commit

Permalink
Auto merge of #95897 - AzureMarker:feature/horizon-std, r=nagisa
Browse files Browse the repository at this point in the history
STD support for the Nintendo 3DS

Rustc already supports compiling for the Nintendo 3DS using the `armv6k-nintendo-3ds` target (Tier 3). Until now though, only `core` and `alloc` were supported. This PR adds standard library support for the Nintendo 3DS. A notable exclusion is `std::thread` support, which will come in a follow-up PR as it requires more complicated changes.

This has been a joint effort by `@Meziu,` `@ian-h-chamberlain,` myself, and prior work by `@rust3ds` members.

### Background

The Nintendo 3DS (Horizon OS) is a mostly-UNIX looking system, with the caveat that it does not come with a full libc implementation out of the box. On the homebrew side (I'm not under NDA), the libc interface is partially implemented by the [devkitPro](https://devkitpro.org/wiki/devkitPro_pacman) toolchain and a user library like [`libctru`](https://github.com/devkitPro/libctru). This is important because there are [some possible legal barriers](rust-lang/rust#88529 (comment)) to linking directly to a library that uses the underlying platform APIs, since they might be considered a trade secret or under NDA.

To get around this, the standard library impl for the 3DS does not directly depend on any platform-level APIs. Instead, it expects standard libc functions to be linked in. The implementation of these libc functions is left to the user. Some functions are provided by the devkitPro toolchain, but in our testing, we used the following to fill in the other functions:
- [`libctru`] - provides more basic APIs, such as `nanosleep`. Linked in by way of [`ctru-sys`](https://github.com/Meziu/ctru-rs/tree/master/ctru-sys).
- [`pthread-3ds`](https://github.com/Meziu/pthread-3ds) - provides pthread APIs for `std::thread`. Implemented using [`libctru`].
- [`linker-fix-3ds`](https://github.com/Meziu/rust-linker-fix-3ds) - fulfills some other missing libc APIs. Implemented using [`libctru`].

For more details, see the `src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md` file added in this PR.

### Notes
We've already upstreamed changes to the [`libc`] crate to support this PR, as well as the upcoming threading PR. These changes have all been released as of 0.2.121, so we bump the crate version in this PR.
Edit: After some rebases, the version bump has already been merged so it doesn't appear in this PR.

A lot of the changes in this PR are straightforward, and follow in the footsteps of the ESP-IDF target: rust-lang/rust#87666.

The 3DS does not support user space process spawning, so these APIs are unimplemented (similar to ESP-IDF).

[`libctru`]: https://github.com/devkitPro/libctru
[`libc`]: https://github.com/rust-lang/libc
  • Loading branch information
bors committed Jun 15, 2022
2 parents a6521f4 + 8217657 commit 24468e1
Show file tree
Hide file tree
Showing 23 changed files with 303 additions and 87 deletions.
3 changes: 2 additions & 1 deletion core/src/ffi/mod.rs
Expand Up @@ -143,7 +143,8 @@ mod c_char_definition {
target_arch = "powerpc"
)
),
all(target_os = "fuchsia", target_arch = "aarch64")
all(target_os = "fuchsia", target_arch = "aarch64"),
target_os = "horizon"
))] {
pub type c_char = u8;
pub type NonZero_c_char = crate::num::NonZeroU8;
Expand Down
1 change: 1 addition & 0 deletions std/build.rs
Expand Up @@ -29,6 +29,7 @@ fn main() {
|| target.contains("asmjs")
|| target.contains("espidf")
|| target.contains("solid")
|| target.contains("nintendo-3ds")
{
// These platforms don't have any special requirements.
} else {
Expand Down
95 changes: 95 additions & 0 deletions std/src/os/horizon/fs.rs
@@ -0,0 +1,95 @@
#![stable(feature = "metadata_ext", since = "1.1.0")]

use crate::fs::Metadata;
use crate::sys_common::AsInner;

/// OS-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: crate::fs::Metadata
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_dev(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ino(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mode(&self) -> u32;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_nlink(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_uid(&self) -> u32;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_gid(&self) -> u32;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_rdev(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_size(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blksize(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blocks(&self) -> u64;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
fn st_dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn st_ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn st_mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn st_nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn st_uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn st_gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn st_rdev(&self) -> u64 {
self.as_inner().as_inner().st_rdev as u64
}
fn st_size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn st_atime(&self) -> i64 {
self.as_inner().as_inner().st_atim.tv_sec
}
fn st_atime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_atim.tv_nsec as i64
}
fn st_mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtim.tv_sec
}
fn st_mtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_mtim.tv_nsec as i64
}
fn st_ctime(&self) -> i64 {
self.as_inner().as_inner().st_ctim.tv_sec
}
fn st_ctime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_ctim.tv_nsec as i64
}
fn st_blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn st_blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
}
6 changes: 6 additions & 0 deletions std/src/os/horizon/mod.rs
@@ -0,0 +1,6 @@
//! Definitions for Horizon OS

#![stable(feature = "raw_ext", since = "1.1.0")]

pub mod fs;
pub(crate) mod raw;
70 changes: 70 additions & 0 deletions std/src/os/horizon/raw.rs
@@ -0,0 +1,70 @@
//! Horizon OS raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]
#![deprecated(
since = "1.8.0",
note = "these type aliases are no longer supported by \
the standard library, the `libc` crate on \
crates.io should be used instead for the correct \
definitions"
)]
#![allow(deprecated)]

use crate::os::raw::c_long;
use crate::os::unix::raw::{gid_t, uid_t};

#[stable(feature = "pthread_t", since = "1.8.0")]
pub type pthread_t = libc::pthread_t;

#[stable(feature = "raw_ext", since = "1.1.0")]
pub type blkcnt_t = libc::blkcnt_t;

#[stable(feature = "raw_ext", since = "1.1.0")]
pub type blksize_t = libc::blksize_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type dev_t = libc::dev_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type ino_t = libc::ino_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type mode_t = libc::mode_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type nlink_t = libc::nlink_t;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type off_t = libc::off_t;

#[stable(feature = "raw_ext", since = "1.1.0")]
pub type time_t = libc::time_t;

#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_dev: dev_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ino: ino_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mode: mode_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_nlink: nlink_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_uid: uid_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gid: gid_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_rdev: dev_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: off_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blksize: blksize_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: blkcnt_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_spare4: [c_long; 2usize],
}
2 changes: 2 additions & 0 deletions std/src/os/mod.rs
Expand Up @@ -123,6 +123,8 @@ pub mod freebsd;
pub mod fuchsia;
#[cfg(target_os = "haiku")]
pub mod haiku;
#[cfg(target_os = "horizon")]
pub mod horizon;
#[cfg(target_os = "illumos")]
pub mod illumos;
#[cfg(target_os = "ios")]
Expand Down
2 changes: 2 additions & 0 deletions std/src/os/unix/mod.rs
Expand Up @@ -51,6 +51,8 @@ mod platform {
pub use crate::os::fuchsia::*;
#[cfg(target_os = "haiku")]
pub use crate::os::haiku::*;
#[cfg(target_os = "horizon")]
pub use crate::os::horizon::*;
#[cfg(target_os = "illumos")]
pub use crate::os::illumos::*;
#[cfg(target_os = "ios")]
Expand Down
46 changes: 16 additions & 30 deletions std/src/os/unix/process.rs
Expand Up @@ -12,6 +12,16 @@ use crate::sealed::Sealed;
use crate::sys;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};

#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
type UserId = u32;
#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
type GroupId = u32;

#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
type UserId = u16;
#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
type GroupId = u16;

/// Unix-specific extensions to the [`process::Command`] builder.
///
/// This trait is sealed: it cannot be implemented outside the standard library.
Expand All @@ -22,29 +32,17 @@ pub trait CommandExt: Sealed {
/// `setuid` call in the child process. Failure in the `setuid`
/// call will cause the spawn to fail.
#[stable(feature = "rust1", since = "1.0.0")]
fn uid(
&mut self,
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command;
fn uid(&mut self, id: UserId) -> &mut process::Command;

/// Similar to `uid`, but sets the group ID of the child process. This has
/// the same semantics as the `uid` field.
#[stable(feature = "rust1", since = "1.0.0")]
fn gid(
&mut self,
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command;
fn gid(&mut self, id: GroupId) -> &mut process::Command;

/// Sets the supplementary group IDs for the calling process. Translates to
/// a `setgroups` call in the child process.
#[unstable(feature = "setgroups", issue = "90747")]
fn groups(
&mut self,
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
) -> &mut process::Command;
fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command;

/// Schedules a closure to be run just before the `exec` function is
/// invoked.
Expand Down Expand Up @@ -158,29 +156,17 @@ pub trait CommandExt: Sealed {

#[stable(feature = "rust1", since = "1.0.0")]
impl CommandExt for process::Command {
fn uid(
&mut self,
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command {
fn uid(&mut self, id: UserId) -> &mut process::Command {
self.as_inner_mut().uid(id);
self
}

fn gid(
&mut self,
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
) -> &mut process::Command {
fn gid(&mut self, id: GroupId) -> &mut process::Command {
self.as_inner_mut().gid(id);
self
}

fn groups(
&mut self,
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
) -> &mut process::Command {
fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command {
self.as_inner_mut().groups(groups);
self
}
Expand Down
3 changes: 2 additions & 1 deletion std/src/sys/unix/alloc.rs
Expand Up @@ -58,7 +58,8 @@ cfg_if::cfg_if! {
target_os = "illumos",
target_os = "redox",
target_os = "solaris",
target_os = "espidf"
target_os = "espidf",
target_os = "horizon"
))] {
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
Expand Down
3 changes: 2 additions & 1 deletion std/src/sys/unix/args.rs
Expand Up @@ -68,7 +68,8 @@ impl DoubleEndedIterator for Args {
target_os = "l4re",
target_os = "fuchsia",
target_os = "redox",
target_os = "vxworks"
target_os = "vxworks",
target_os = "horizon"
))]
mod imp {
use super::Args;
Expand Down
11 changes: 11 additions & 0 deletions std/src/sys/unix/env.rs
Expand Up @@ -119,6 +119,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}

#[cfg(target_os = "horizon")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "horizon";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = ".elf";
pub const EXE_EXTENSION: &str = "elf";
}

#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
pub mod os {
pub const FAMILY: &str = "unix";
Expand Down

0 comments on commit 24468e1

Please sign in to comment.