Skip to content

Commit 761310d

Browse files
bors[bot]Johnathan Van Why
and
Johnathan Van Why
authored
Merge #290
290: Replace `*mut ()` with a new `Register` wrapper in `RawSyscalls`. r=hudson-ayers a=jrvanwhy This change makes it easier to replace the `*mut ()` type in `RawSyscalls` with another type. I also removed `/platform` from `.gitignore`, as it was making `git` ignore new files in the `libtock_platform` crate. This is an alternative to #289, which achieves the same goal by using a type alias. Co-authored-by: Johnathan Van Why <[email protected]>
2 parents c59bb74 + 8d85f2b commit 761310d

File tree

8 files changed

+155
-59
lines changed

8 files changed

+155
-59
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
/Cargo.lock
2-
/platform
32
/target

platform/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod async_traits;
55
mod command_return;
66
mod error_code;
77
mod raw_syscalls;
8+
mod register;
89
pub mod return_variant;
910
mod syscalls;
1011
mod syscalls_impl;
@@ -14,6 +15,7 @@ pub use async_traits::{CallbackContext, FreeCallback, Locator, MethodCallback};
1415
pub use command_return::CommandReturn;
1516
pub use error_code::ErrorCode;
1617
pub use raw_syscalls::RawSyscalls;
18+
pub use register::Register;
1719
pub use return_variant::ReturnVariant;
1820
pub use syscalls::Syscalls;
1921
pub use yield_types::YieldNoWaitReturn;

platform/src/raw_syscalls.rs

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// TODO: Implement `libtock_unittest`, which is referenced in the comment on
22
// `RawSyscalls`.
33

4+
use crate::Register;
5+
46
/// `RawSyscalls` allows a fake Tock kernel to be injected into components for
57
/// unit testing. It is implemented by `libtock_runtime::TockSyscalls` and
68
/// `libtock_unittest::fake::Kernel`. **Components should not use `RawSyscalls`
@@ -19,50 +21,44 @@
1921
// Theoretically, RawSyscalls could consist of a single raw system call. To
2022
// start, something like this should work:
2123
//
22-
// unsafe fn syscall<const CLASS: usize>([usize; 4]) -> [usize; 4];
23-
//
24-
// However, this will not work with Miri's -Zmiri-track-raw-pointers flag, as it
25-
// causes pointers passed to the kernel via the Allow system calls to be
26-
// untagged. In order to work with -Zmiri-track-raw-pointers, we need to pass
27-
// pointers for the register values. Rust's closest analogue to C's void pointer
28-
// is *mut () or *const (); we use *mut () because it is shorter:
24+
// unsafe fn syscall<const CLASS: usize>([Reg; 4]) -> [Reg; 4];
2925
//
30-
// unsafe fn syscall<const CLASS: usize>([*mut (); 4]) -> [*mut (); 4];
26+
// Note: Reg is an abbreviation of Register.
3127
//
3228
// Using a single system call has a major inefficiency. The single raw system
3329
// call would need to clobber every register that any system call can clobber.
3430
// Yield has a far longer clobber list than most system calls, so this would be
3531
// inefficient for the majority of system calls. As a result, we can split yield
3632
// out into its own function, giving the following API:
3733
//
38-
// unsafe fn yield([*mut (); 4]) -> [*mut (); 4];
39-
// unsafe fn syscall<const CLASS: usize>([*mut (); 4]) -> [*mut (); 4];
34+
// unsafe fn yield([Reg; 4]) -> [Reg; 4];
35+
// unsafe fn syscall<const CLASS: usize>([Reg; 4]) -> [Reg; 4];
4036
//
4137
// There is one significant inefficiency remaining. Many system calls, such as
4238
// memop's "get RAM start address" operation, do not need to set all four
4339
// arguments. The compiler cannot optimize away this inefficiency, so to remove
4440
// it we need to split the system calls up based on the number of arguments they
4541
// take:
4642
//
47-
// unsafe fn yield0([*mut (); 0]) -> [*mut (); 4];
48-
// unsafe fn yield1([*mut (); 1]) -> [*mut (); 4];
49-
// unsafe fn yield2([*mut (); 2]) -> [*mut (); 4];
50-
// unsafe fn yield3([*mut (); 3]) -> [*mut (); 4];
51-
// unsafe fn yield4([*mut (); 4]) -> [*mut (); 4];
52-
// unsafe fn syscall0<const CLASS: usize>([*mut (); 0]) -> [*mut (); 4];
53-
// unsafe fn syscall1<const CLASS: usize>([*mut (); 1]) -> [*mut (); 4];
54-
// unsafe fn syscall2<const CLASS: usize>([*mut (); 2]) -> [*mut (); 4];
55-
// unsafe fn syscall3<const CLASS: usize>([*mut (); 3]) -> [*mut (); 4];
56-
// unsafe fn syscall4<const CLASS: usize>([*mut (); 4]) -> [*mut (); 4];
43+
// unsafe fn yield0([Reg; 0]) -> [Reg; 4];
44+
// unsafe fn yield1([Reg; 1]) -> [Reg; 4];
45+
// unsafe fn yield2([Reg; 2]) -> [Reg; 4];
46+
// unsafe fn yield3([Reg; 3]) -> [Reg; 4];
47+
// unsafe fn yield4([Reg; 4]) -> [Reg; 4];
48+
// unsafe fn syscall0<const CLASS: usize>([Reg; 0]) -> [Reg; 4];
49+
// unsafe fn syscall1<const CLASS: usize>([Reg; 1]) -> [Reg; 4];
50+
// unsafe fn syscall2<const CLASS: usize>([Reg; 2]) -> [Reg; 4];
51+
// unsafe fn syscall3<const CLASS: usize>([Reg; 3]) -> [Reg; 4];
52+
// unsafe fn syscall4<const CLASS: usize>([Reg; 4]) -> [Reg; 4];
5753
//
5854
// However, not all of these are used! If we remove the system calls that are
5955
// unused, we are left with the following:
6056
//
61-
// unsafe fn yield1([*mut (); 1]) -> [*mut (); 4];
62-
// unsafe fn yield2([*mut (); 2]) -> [*mut (); 4];
63-
// unsafe fn syscall1<const CLASS: usize>([*mut (); 1]) -> [*mut (); 4];
64-
// unsafe fn syscall2<const CLASS: usize>([*mut (); 2]) -> [*mut (); 4];
65-
// unsafe fn syscall4<const CLASS: usize>([*mut (); 4]) -> [*mut (); 4];
57+
// unsafe fn yield1([Reg; 1]) -> [Reg; 4];
58+
// unsafe fn yield2([Reg; 2]) -> [Reg; 4];
59+
// unsafe fn syscall1<const CLASS: usize>([Reg; 1]) -> [Reg; 4];
60+
// unsafe fn syscall2<const CLASS: usize>([Reg; 2]) -> [Reg; 4];
61+
// unsafe fn syscall4<const CLASS: usize>([Reg; 4]) -> [Reg; 4];
6662
//
6763
// These system calls are refined further individually, which is documented on
6864
// a per-function basis.
@@ -86,7 +82,7 @@ pub unsafe trait RawSyscalls {
8682
/// # Safety
8783
/// yield1 may only be used for yield operations that do not return a value.
8884
/// It is exactly as safe as the underlying system call.
89-
unsafe fn yield1(_: [*mut (); 1]);
85+
unsafe fn yield1(_: [Register; 1]);
9086

9187
// yield2 can only be used to call `yield-no-wait`. `yield-no-wait` does not
9288
// return any values, so to simplify the assembly we omit return arguments.
@@ -106,7 +102,7 @@ pub unsafe trait RawSyscalls {
106102
/// # Safety
107103
/// yield2 may only be used for yield operations that do not return a value.
108104
/// It has the same safety invariants as the underlying system call.
109-
unsafe fn yield2(_: [*mut (); 2]);
105+
unsafe fn yield2(_: [Register; 2]);
110106

111107
// syscall1 is only used to invoke Memop operations. Because there are no
112108
// Memop commands that set r2 or r3, raw_syscall1 only needs to return r0
@@ -135,7 +131,7 @@ pub unsafe trait RawSyscalls {
135131
/// This directly makes a system call. It can only be used for core kernel
136132
/// system calls that accept 1 argument and only overwrite r0 and r1 on
137133
/// return. It is unsafe any time the underlying system call is unsafe.
138-
unsafe fn syscall1<const CLASS: usize>(_: [*mut (); 1]) -> [*mut (); 2];
134+
unsafe fn syscall1<const CLASS: usize>(_: [Register; 1]) -> [Register; 2];
139135

140136
// syscall2 is used to invoke Exit as well as Memop operations that take an
141137
// argument. Memop does not currently use more than 2 registers for its
@@ -160,7 +156,7 @@ pub unsafe trait RawSyscalls {
160156
/// `syscall2` directly makes a system call. It can only be used for core
161157
/// kernel system calls that accept 2 arguments and only overwrite r0 and r1
162158
/// on return. It is unsafe any time the underlying system call is unsafe.
163-
unsafe fn syscall2<const CLASS: usize>(_: [*mut (); 2]) -> [*mut (); 2];
159+
unsafe fn syscall2<const CLASS: usize>(_: [Register; 2]) -> [Register; 2];
164160

165161
// syscall4 should:
166162
// 1. Call the syscall class specified by CLASS.
@@ -183,5 +179,5 @@ pub unsafe trait RawSyscalls {
183179
/// `syscall4` must NOT be used to invoke yield. Otherwise, it has the same
184180
/// safety invariants as the underlying system call, which varies depending
185181
/// on the system call class.
186-
unsafe fn syscall4<const CLASS: usize>(_: [*mut (); 4]) -> [*mut (); 4];
182+
unsafe fn syscall4<const CLASS: usize>(_: [Register; 4]) -> [Register; 4];
187183
}

platform/src/register.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/// In order to work with Miri's `-Zmiri-track-raw-pointers` flag, we cannot
2+
/// pass pointers to the kernel through `usize` values (as casting to and from
3+
/// `usize` drops the pointer`s tag). Instead, `RawSyscalls` uses the `Register`
4+
/// type. `Register` wraps a raw pointer type that keeps that tags around. User
5+
/// code should not depend on the particular type of pointer that `Register`
6+
/// wraps, but instead use the conversion functions in this module.
7+
#[derive(Clone, Copy, Debug)]
8+
pub struct Register(pub *mut ());
9+
10+
// -----------------------------------------------------------------------------
11+
// Conversions to Register
12+
// -----------------------------------------------------------------------------
13+
14+
impl From<u32> for Register {
15+
fn from(value: u32) -> Register {
16+
Register(value as *mut ())
17+
}
18+
}
19+
20+
impl From<usize> for Register {
21+
fn from(value: usize) -> Register {
22+
Register(value as *mut ())
23+
}
24+
}
25+
26+
impl<T> From<*mut T> for Register {
27+
fn from(value: *mut T) -> Register {
28+
Register(value as *mut ())
29+
}
30+
}
31+
32+
impl<T> From<*const T> for Register {
33+
fn from(value: *const T) -> Register {
34+
Register(value as *mut ())
35+
}
36+
}
37+
38+
// -----------------------------------------------------------------------------
39+
// Infallible conversions from Register
40+
// -----------------------------------------------------------------------------
41+
42+
// If we implement From<u32> on Register, then we automatically get a
43+
// TryFrom<Error = Infallible> implementation, which conflicts with our fallible
44+
// TryFrom implementation. We could choose to not implement TryFrom and instead
45+
// add a fallible accessor (something like "expect_u32"), but that seems
46+
// confusing. Instead, we use an inherent method for the Register -> u32
47+
// infallible conversion.
48+
impl Register {
49+
/// Casts this register to a u32, truncating it if it is larger than
50+
/// u32::MAX. This conversion should be avoided in host-based test code; use
51+
/// the `TryFrom<Register> for u32` implementation instead.
52+
pub fn as_u32(self) -> u32 {
53+
self.0 as u32
54+
}
55+
}
56+
57+
impl From<Register> for usize {
58+
fn from(register: Register) -> usize {
59+
register.0 as usize
60+
}
61+
}
62+
63+
impl<T> From<Register> for *mut T {
64+
fn from(register: Register) -> *mut T {
65+
register.0 as *mut T
66+
}
67+
}
68+
69+
impl<T> From<Register> for *const T {
70+
fn from(register: Register) -> *const T {
71+
register.0 as *const T
72+
}
73+
}
74+
75+
// -----------------------------------------------------------------------------
76+
// Fallible conversions from Register
77+
// -----------------------------------------------------------------------------
78+
79+
/// Converts a `Register` to a `u32`. Returns an error if the `Register`'s value
80+
/// is larger than `u32::MAX`. This is intended for use in host-based tests; in
81+
/// Tock process binary code, use Register::as_u32 instead.
82+
impl core::convert::TryFrom<Register> for u32 {
83+
type Error = core::num::TryFromIntError;
84+
85+
fn try_from(register: Register) -> Result<u32, core::num::TryFromIntError> {
86+
use core::convert::TryInto;
87+
(register.0 as usize).try_into()
88+
}
89+
}

platform/src/syscalls_impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl<S: RawSyscalls> Syscalls for S {
1919
// Flag can be uninitialized here because the kernel promises to
2020
// only write to it, not read from it. MaybeUninit guarantees that
2121
// it is safe to write a YieldNoWaitReturn into it.
22-
Self::yield2([yield_op::NO_WAIT as *mut (), flag.as_mut_ptr() as *mut ()]);
22+
Self::yield2([yield_op::NO_WAIT.into(), flag.as_mut_ptr().into()]);
2323

2424
// yield-no-wait guarantees it sets (initializes) flag before
2525
// returning.
@@ -32,7 +32,7 @@ impl<S: RawSyscalls> Syscalls for S {
3232
// requirement. The yield-wait system call cannot trigger undefined
3333
// behavior on its own in any other way.
3434
unsafe {
35-
Self::yield1([yield_op::WAIT as *mut ()]);
35+
Self::yield1([yield_op::WAIT.into()]);
3636
}
3737
}
3838
}

runtime/src/syscalls_impl_arm.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use libtock_platform::RawSyscalls;
1+
use libtock_platform::{RawSyscalls, Register};
22

33
unsafe impl RawSyscalls for crate::TockSyscalls {
4-
unsafe fn yield1([r0]: [*mut (); 1]) {
4+
unsafe fn yield1([Register(r0)]: [Register; 1]) {
55
// Safety: This matches the invariants required by the documentation on
66
// RawSyscalls::yield1
77
unsafe {
@@ -22,7 +22,7 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
2222
}
2323
}
2424

25-
unsafe fn yield2([r0, r1]: [*mut (); 2]) {
25+
unsafe fn yield2([Register(r0), Register(r1)]: [Register; 2]) {
2626
// Safety: This matches the invariants required by the documentation on
2727
// RawSyscalls::yield2
2828
unsafe {
@@ -43,7 +43,7 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
4343
}
4444
}
4545

46-
unsafe fn syscall1<const CLASS: usize>([mut r0]: [*mut (); 1]) -> [*mut (); 2] {
46+
unsafe fn syscall1<const CLASS: usize>([Register(mut r0)]: [Register; 1]) -> [Register; 2] {
4747
let r1;
4848
// Safety: This matches the invariants required by the documentation on
4949
// RawSyscalls::syscall1
@@ -55,10 +55,12 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
5555
options(preserves_flags, nostack, nomem),
5656
);
5757
}
58-
[r0, r1]
58+
[Register(r0), Register(r1)]
5959
}
6060

61-
unsafe fn syscall2<const CLASS: usize>([mut r0, mut r1]: [*mut (); 2]) -> [*mut (); 2] {
61+
unsafe fn syscall2<const CLASS: usize>(
62+
[Register(mut r0), Register(mut r1)]: [Register; 2],
63+
) -> [Register; 2] {
6264
// Safety: This matches the invariants required by the documentation on
6365
// RawSyscalls::syscall2
6466
unsafe {
@@ -69,12 +71,12 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
6971
options(preserves_flags, nostack, nomem)
7072
);
7173
}
72-
[r0, r1]
74+
[Register(r0), Register(r1)]
7375
}
7476

7577
unsafe fn syscall4<const CLASS: usize>(
76-
[mut r0, mut r1, mut r2, mut r3]: [*mut (); 4],
77-
) -> [*mut (); 4] {
78+
[Register(mut r0), Register(mut r1), Register(mut r2), Register(mut r3)]: [Register; 4],
79+
) -> [Register; 4] {
7880
// Safety: This matches the invariants required by the documentation on
7981
// RawSyscalls::syscall4
8082
unsafe {
@@ -87,6 +89,6 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
8789
options(preserves_flags, nostack),
8890
);
8991
}
90-
[r0, r1, r2, r3]
92+
[Register(r0), Register(r1), Register(r2), Register(r3)]
9193
}
9294
}

runtime/src/syscalls_impl_riscv.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use libtock_platform::RawSyscalls;
1+
use libtock_platform::{RawSyscalls, Register};
22

33
unsafe impl RawSyscalls for crate::TockSyscalls {
44
// This yield implementation is currently limited to RISC-V versions without
55
// floating-point registers, as it does not mark them clobbered.
66
#[cfg(not(any(target_feature = "d", target_feature = "f")))]
7-
unsafe fn yield1([r0]: [*mut (); 1]) {
7+
unsafe fn yield1([Register(r0)]: [Register; 1]) {
88
// Safety: This matches the invariants required by the documentation on
99
// RawSyscalls::yield1
1010
unsafe {
@@ -37,7 +37,7 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
3737
// This yield implementation is currently limited to RISC-V versions without
3838
// floating-point registers, as it does not mark them clobbered.
3939
#[cfg(not(any(target_feature = "d", target_feature = "f")))]
40-
unsafe fn yield2([r0, r1]: [*mut (); 2]) {
40+
unsafe fn yield2([Register(r0), Register(r1)]: [Register; 2]) {
4141
// Safety: This matches the invariants required by the documentation on
4242
// RawSyscalls::yield2
4343
unsafe {
@@ -67,7 +67,7 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
6767
}
6868
}
6969

70-
unsafe fn syscall1<const CLASS: usize>([mut r0]: [*mut (); 1]) -> [*mut (); 2] {
70+
unsafe fn syscall1<const CLASS: usize>([Register(mut r0)]: [Register; 1]) -> [Register; 2] {
7171
let r1;
7272
// Safety: This matches the invariants required by the documentation on
7373
// RawSyscalls::syscall1
@@ -79,10 +79,12 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
7979
options(preserves_flags, nostack, nomem),
8080
);
8181
}
82-
[r0, r1]
82+
[Register(r0), Register(r1)]
8383
}
8484

85-
unsafe fn syscall2<const CLASS: usize>([mut r0, mut r1]: [*mut (); 2]) -> [*mut (); 2] {
85+
unsafe fn syscall2<const CLASS: usize>(
86+
[Register(mut r0), Register(mut r1)]: [Register; 2],
87+
) -> [Register; 2] {
8688
// Safety: This matches the invariants required by the documentation on
8789
// RawSyscalls::syscall2
8890
unsafe {
@@ -93,12 +95,12 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
9395
options(preserves_flags, nostack, nomem)
9496
);
9597
}
96-
[r0, r1]
98+
[Register(r0), Register(r1)]
9799
}
98100

99101
unsafe fn syscall4<const CLASS: usize>(
100-
[mut r0, mut r1, mut r2, mut r3]: [*mut (); 4],
101-
) -> [*mut (); 4] {
102+
[Register(mut r0), Register(mut r1), Register(mut r2), Register(mut r3)]: [Register; 4],
103+
) -> [Register; 4] {
102104
// Safety: This matches the invariants required by the documentation on
103105
// RawSyscalls::syscall4
104106
unsafe {
@@ -111,6 +113,6 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
111113
options(preserves_flags, nostack),
112114
);
113115
}
114-
[r0, r1, r2, r3]
116+
[Register(r0), Register(r1), Register(r2), Register(r3)]
115117
}
116118
}

0 commit comments

Comments
 (0)