Skip to content

Commit 150a9c2

Browse files
committed
std: xous: add support for args and env
Process arguments and environment variables are both passed by way of Application Parameters. These are a TLV format that gets passed in as the second process argument. This patch combines both as they are very similar in their decode. Signed-off-by: Sean Cross <[email protected]>
1 parent dcdb192 commit 150a9c2

File tree

5 files changed

+500
-32
lines changed

5 files changed

+500
-32
lines changed

library/std/src/sys/pal/xous/args.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use crate::ffi::OsString;
2+
use crate::sys::pal::xous::os::{get_application_parameters, params::ArgumentList};
3+
use crate::{fmt, vec};
4+
5+
pub struct Args {
6+
parsed_args_list: vec::IntoIter<OsString>,
7+
}
8+
9+
pub fn args() -> Args {
10+
let Some(params) = get_application_parameters() else {
11+
return Args { parsed_args_list: vec![].into_iter() };
12+
};
13+
14+
for param in params {
15+
if let Ok(args) = ArgumentList::try_from(&param) {
16+
let mut parsed_args = vec![];
17+
for arg in args {
18+
parsed_args.push(arg.into());
19+
}
20+
return Args { parsed_args_list: parsed_args.into_iter() };
21+
}
22+
}
23+
Args { parsed_args_list: vec![].into_iter() }
24+
}
25+
26+
impl fmt::Debug for Args {
27+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28+
self.parsed_args_list.as_slice().fmt(f)
29+
}
30+
}
31+
32+
impl Iterator for Args {
33+
type Item = OsString;
34+
fn next(&mut self) -> Option<OsString> {
35+
self.parsed_args_list.next()
36+
}
37+
fn size_hint(&self) -> (usize, Option<usize>) {
38+
self.parsed_args_list.size_hint()
39+
}
40+
}
41+
42+
impl DoubleEndedIterator for Args {
43+
fn next_back(&mut self) -> Option<OsString> {
44+
self.parsed_args_list.next_back()
45+
}
46+
}
47+
48+
impl ExactSizeIterator for Args {
49+
fn len(&self) -> usize {
50+
self.parsed_args_list.len()
51+
}
52+
}

library/std/src/sys/pal/xous/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![forbid(unsafe_op_in_unsafe_fn)]
22

3-
#[path = "../unsupported/args.rs"]
43
pub mod args;
54
#[path = "../unsupported/env.rs"]
65
pub mod env;

library/std/src/sys/pal/xous/os.rs

Lines changed: 107 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
11
use super::unsupported;
2+
use crate::collections::HashMap;
23
use crate::error::Error as StdError;
34
use crate::ffi::{OsStr, OsString};
45
use crate::marker::PhantomData;
56
use crate::os::xous::ffi::Error as XousError;
67
use crate::path::{self, PathBuf};
7-
use crate::{fmt, io};
8+
use crate::sync::{
9+
atomic::{AtomicPtr, AtomicUsize, Ordering},
10+
Mutex, Once,
11+
};
12+
use crate::{fmt, io, vec};
13+
14+
pub(crate) mod params;
15+
16+
static PARAMS_ADDRESS: AtomicPtr<u8> = AtomicPtr::new(core::ptr::null_mut());
817

918
#[cfg(not(test))]
1019
#[cfg(feature = "panic_unwind")]
1120
mod eh_unwinding {
12-
pub(crate) struct EhFrameFinder(usize /* eh_frame */);
13-
pub(crate) static mut EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder(0);
14-
impl EhFrameFinder {
15-
pub(crate) unsafe fn init(&mut self, eh_frame: usize) {
16-
unsafe {
17-
EH_FRAME_SETTINGS.0 = eh_frame;
18-
}
19-
}
20-
}
21+
pub(crate) struct EhFrameFinder;
22+
pub(crate) static mut EH_FRAME_ADDRESS: usize = 0;
23+
pub(crate) static EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder;
24+
2125
unsafe impl unwind::EhFrameFinder for EhFrameFinder {
2226
fn find(&self, _pc: usize) -> Option<unwind::FrameInfo> {
23-
Some(unwind::FrameInfo {
24-
text_base: None,
25-
kind: unwind::FrameInfoKind::EhFrame(self.0),
26-
})
27+
if unsafe { EH_FRAME_ADDRESS == 0 } {
28+
None
29+
} else {
30+
Some(unwind::FrameInfo {
31+
text_base: None,
32+
kind: unwind::FrameInfoKind::EhFrame(unsafe { EH_FRAME_ADDRESS }),
33+
})
34+
}
2735
}
2836
}
2937
}
@@ -41,12 +49,21 @@ mod c_compat {
4149
}
4250

4351
#[no_mangle]
44-
pub extern "C" fn _start(eh_frame: usize) {
52+
pub extern "C" fn _start(eh_frame: usize, params_address: usize) {
4553
#[cfg(feature = "panic_unwind")]
46-
unsafe {
47-
super::eh_unwinding::EH_FRAME_SETTINGS.init(eh_frame);
54+
{
55+
unsafe { super::eh_unwinding::EH_FRAME_ADDRESS = eh_frame };
4856
unwind::set_custom_eh_frame_finder(&super::eh_unwinding::EH_FRAME_SETTINGS).ok();
4957
}
58+
59+
if params_address != 0 {
60+
let params_address = crate::ptr::with_exposed_provenance_mut::<u8>(params_address);
61+
if unsafe {
62+
super::params::ApplicationParameters::new_from_ptr(params_address).is_some()
63+
} {
64+
super::PARAMS_ADDRESS.store(params_address, core::sync::atomic::Ordering::Relaxed);
65+
}
66+
}
5067
exit(unsafe { main() });
5168
}
5269

@@ -116,44 +133,103 @@ pub fn current_exe() -> io::Result<PathBuf> {
116133
unsupported()
117134
}
118135

119-
pub struct Env(!);
136+
pub(crate) fn get_application_parameters() -> Option<params::ApplicationParameters> {
137+
let params_address = PARAMS_ADDRESS.load(Ordering::Relaxed);
138+
unsafe { params::ApplicationParameters::new_from_ptr(params_address) }
139+
}
140+
141+
// ---------- Environment handling ---------- //
142+
static ENV: AtomicUsize = AtomicUsize::new(0);
143+
static ENV_INIT: Once = Once::new();
144+
type EnvStore = Mutex<HashMap<OsString, OsString>>;
145+
146+
fn get_env_store() -> &'static EnvStore {
147+
ENV_INIT.call_once(|| {
148+
let env_store = EnvStore::default();
149+
if let Some(params) = get_application_parameters() {
150+
for param in params {
151+
if let Ok(envs) = params::EnvironmentBlock::try_from(&param) {
152+
let mut env_store = env_store.lock().unwrap();
153+
for env in envs {
154+
env_store.insert(env.key.into(), env.value.into());
155+
}
156+
break;
157+
}
158+
}
159+
}
160+
ENV.store(Box::into_raw(Box::new(env_store)) as _, Ordering::Relaxed)
161+
});
162+
unsafe { &*core::ptr::with_exposed_provenance::<EnvStore>(ENV.load(Ordering::Relaxed)) }
163+
}
164+
165+
pub struct Env {
166+
iter: vec::IntoIter<(OsString, OsString)>,
167+
}
168+
169+
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
170+
pub struct EnvStrDebug<'a> {
171+
slice: &'a [(OsString, OsString)],
172+
}
173+
174+
impl fmt::Debug for EnvStrDebug<'_> {
175+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176+
let Self { slice } = self;
177+
f.debug_list()
178+
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
179+
.finish()
180+
}
181+
}
120182

121183
impl Env {
122184
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
123185
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
124-
let Self(inner) = self;
125-
match *inner {}
186+
let Self { iter } = self;
187+
EnvStrDebug { slice: iter.as_slice() }
126188
}
127189
}
128190

129191
impl fmt::Debug for Env {
130-
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
131-
let Self(inner) = self;
132-
match *inner {}
192+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193+
let Self { iter } = self;
194+
f.debug_list().entries(iter.as_slice()).finish()
133195
}
134196
}
135197

198+
impl !Send for Env {}
199+
impl !Sync for Env {}
200+
136201
impl Iterator for Env {
137202
type Item = (OsString, OsString);
138203
fn next(&mut self) -> Option<(OsString, OsString)> {
139-
self.0
204+
self.iter.next()
205+
}
206+
fn size_hint(&self) -> (usize, Option<usize>) {
207+
self.iter.size_hint()
140208
}
141209
}
142210

143211
pub fn env() -> Env {
144-
panic!("not supported on this platform")
212+
let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> {
213+
map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
214+
};
215+
216+
let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter();
217+
Env { iter }
145218
}
146219

147-
pub fn getenv(_: &OsStr) -> Option<OsString> {
148-
None
220+
pub fn getenv(k: &OsStr) -> Option<OsString> {
221+
get_env_store().lock().unwrap().get(k).cloned()
149222
}
150223

151-
pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
152-
Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
224+
pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
225+
let (k, v) = (k.to_owned(), v.to_owned());
226+
get_env_store().lock().unwrap().insert(k, v);
227+
Ok(())
153228
}
154229

155-
pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> {
156-
Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
230+
pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> {
231+
get_env_store().lock().unwrap().remove(k);
232+
Ok(())
157233
}
158234

159235
pub fn temp_dir() -> PathBuf {

0 commit comments

Comments
 (0)