Merge #274 274: Add `start_prototype`, a tool used for writing entry point assembly. r=alistair23 a=jrvanwhy This is a Rust version of the entry point. Using it directly is undefined behavior for multiple reasons (Rust assumes the stack is setup and the globals are initialized), but it can be a useful reference while working on a real (assembly) entry point. **Question for reviewers:** Do you think this belongs in the repository? Co-authored-by: Johnathan Van Why <jrvanwhy@google.com>
diff --git a/.cargo/config b/.cargo/config index 96fe275..8292c1c 100644 --- a/.cargo/config +++ b/.cargo/config
@@ -6,10 +6,6 @@ rthumbv7em = "run --release --target=thumbv7em-none-eabi --example" rtv7em = "rthumbv7em" -# Deny warnings on all architectures. build.rustflags cannot be used here as the lower section would override its effect. -[target.'cfg(all())'] -rustflags = ["-D", "warnings"] - # Common settings for all embedded targets [target.'cfg(any(target_arch = "arm", target_arch = "riscv32"))'] rustflags = [
diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 94a8b10..d394011 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml
@@ -12,6 +12,7 @@ - name: Install dependencies run: | + sudo apt-get install binutils-riscv64-unknown-elf cargo install elf2tab --version 0.4.0 - name: Build Hello World
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bdae5f..e9b448b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml
@@ -16,9 +16,9 @@ # Using ubuntu-latest can cause breakage when ubuntu-latest is updated to # point at a new Ubuntu version. Instead, explicitly specify the version, so # we can update when we need to. This *could* break if we don't update it - # until support for 18.04 is dropped, but it is likely we'll have a reason + # until support for 20.04 is dropped, but it is likely we'll have a reason # to update to a newer Ubuntu before then anyway. - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: # Clones a single commit from the libtock-rs repository. The commit cloned @@ -35,8 +35,16 @@ # makefile can be tested locally. We experimentally determined that -j2 is # optimal for the Azure Standard_DS2_v2 VM, which is the VM type used by # GitHub Actions at the time of this writing. + # + # We have to append the "-D warnings" flag to .cargo/config rather than + # using the RUSTFLAGS environment variable because if we set RUSTFLAGS + # cargo will ignore the rustflags config in .cargo/config, breaking + # relocation. - name: Build and Test run: | + sudo apt-get install binutils-riscv64-unknown-elf cd "${GITHUB_WORKSPACE}" + echo "[target.'cfg(all())']" >> .cargo/config + echo 'rustflags = ["-D", "warnings"]' >> .cargo/config make -j2 setup make -j2 test
diff --git a/.github/workflows/mac-os.yml b/.github/workflows/mac-os.yml new file mode 100644 index 0000000..c813ace --- /dev/null +++ b/.github/workflows/mac-os.yml
@@ -0,0 +1,27 @@ +# This workflow verifies libtock-rs is usable on Mac OS. + +name: ci-mac-os + +# We run this workflow during pull request review, but not for Bors merges, as +# it takes over an hour to run. +on: pull_request + +jobs: + ci-mac-os: + runs-on: macos-10.15 + + steps: + # Clones a single commit from the libtock-rs repository. The commit cloned + # is a merge commit between the PR's target branch and the PR's source. + - name: Clone repository + uses: actions/checkout@v2.3.0 + + # Install the toolchains we need, then run `cargo build`. + - name: Build and Test + run: | + brew tap riscv/riscv + brew update + brew install riscv-gnu-toolchain --with-multilib + cd "${GITHUB_WORKSPACE}" + LIBTOCK_PLATFORM=hifive1 cargo build -p libtock_runtime \ + --target=riscv32imac-unknown-none-elf
diff --git a/.github/workflows/size-diff.yml b/.github/workflows/size-diff.yml index cbf2939..33a0870 100644 --- a/.github/workflows/size-diff.yml +++ b/.github/workflows/size-diff.yml
@@ -17,9 +17,9 @@ # Using ubuntu-latest can cause breakage when ubuntu-latest is updated to # point at a new Ubuntu version. Instead, explicitly specify the version, so # we can update when we need to. This *could* break if we don't update it - # until support for 18.04 is dropped, but it is likely we'll have a reason + # until support for 20.04 is dropped, but it is likely we'll have a reason # to update to a newer Ubuntu before then anyway. - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: # Clones a single commit from the libtock-rs repository. The commit cloned @@ -39,6 +39,7 @@ # master. - name: Compute sizes run: | + sudo apt-get install binutils-riscv64-unknown-elf UPSTREAM_REMOTE_NAME="${UPSTREAM_REMOTE_NAME:-origin}" GITHUB_BASE_REF="${GITHUB_BASE_REF:-master}" cd "${GITHUB_WORKSPACE}"
diff --git a/Makefile b/Makefile index da40d28..e228ab3 100644 --- a/Makefile +++ b/Makefile
@@ -79,8 +79,9 @@ .PHONY: test test: examples test-qemu-hifive LIBTOCK_PLATFORM=nrf52 PLATFORM=nrf52 cargo fmt --all -- --check - LIBTOCK_PLATFORM=nrf52 PLATFORM=nrf52 cargo clippy --workspace --all-targets - LIBTOCK_PLATFORM=nrf52 PLATFORM=nrf52 cargo miri test --workspace + PLATFORM=nrf52 cargo clippy --all-targets --exclude libtock_runtime --workspace + LIBTOCK_PLATFORM=hifive1 cargo clippy --target=riscv32imac-unknown-none-elf -p libtock_runtime + PLATFORM=nrf52 cargo miri test --exclude libtock_runtime --workspace echo '[ SUCCESS ] libtock-rs tests pass' .PHONY: analyse-stack-sizes
diff --git a/core/platform/src/command_return.rs b/core/platform/src/command_return.rs index 7fa7302..9d84572 100644 --- a/core/platform/src/command_return.rs +++ b/core/platform/src/command_return.rs
@@ -1,22 +1,43 @@ use crate::{return_variant, ErrorCode, ReturnVariant}; +use core::mem::transmute; + /// The response type from `command`. Can represent a successful value or a /// failure. #[derive(Clone, Copy)] pub struct CommandReturn { - pub(crate) return_variant: ReturnVariant, + return_variant: ReturnVariant, // r1, r2, and r3 should only contain 32-bit values. However, these are // converted directly from usizes returned by RawSyscalls::four_arg_syscall. // To avoid casting twice (both when converting to a Command Return and when // calling a get_*() function), we store the usizes directly. Then using the // CommandReturn only involves one conversion for each of r1, r2, and r3, // performed in the get_*() functions. - pub(crate) r1: usize, - pub(crate) r2: usize, - pub(crate) r3: usize, + + // Safety invariant on r1: If return_variant is failure variant, r1 must be + // a valid ErrorCode. + r1: usize, + r2: usize, + r3: usize, } impl CommandReturn { + /// # Safety + /// If return_variant is a failure variant, r1 must be a valid ErrorCode. + #[cfg(test)] // Will be removed when command() is implemented. + pub(crate) unsafe fn new( + return_variant: ReturnVariant, + r1: usize, + r2: usize, + r3: usize, + ) -> Self { + CommandReturn { + return_variant, + r1, + r2, + r3, + } + } // I generally expect CommandReturn to be used with pattern matching, e.g.: // // let command_return = Syscalls::command(314, 1, 1, 2); @@ -85,7 +106,7 @@ if !self.is_failure() { return None; } - Some(self.r1.into()) + Some(unsafe { transmute(self.r1 as u16) }) } /// Returns the error code and value if this CommandReturn is of type @@ -94,7 +115,7 @@ if !self.is_failure_u32() { return None; } - Some((self.r1.into(), self.r2 as u32)) + Some((unsafe { transmute(self.r1 as u16) }, self.r2 as u32)) } /// Returns the error code and return values if this CommandReturn is of @@ -103,7 +124,11 @@ if !self.is_failure_2_u32() { return None; } - Some((self.r1.into(), self.r2 as u32, self.r3 as u32)) + Some(( + unsafe { transmute(self.r1 as u16) }, + self.r2 as u32, + self.r3 as u32, + )) } /// Returns the error code and return value if this CommandReturn is of type @@ -112,7 +137,10 @@ if !self.is_failure_u64() { return None; } - Some((self.r1.into(), self.r2 as u64 + ((self.r3 as u64) << 32))) + Some(( + unsafe { transmute(self.r1 as u16) }, + self.r2 as u64 + ((self.r3 as u64) << 32), + )) } /// Returns the value if this CommandReturn is of type Success with u32.
diff --git a/core/platform/src/command_return_tests.rs b/core/platform/src/command_return_tests.rs index 1712f71..439f9e7 100644 --- a/core/platform/src/command_return_tests.rs +++ b/core/platform/src/command_return_tests.rs
@@ -1,12 +1,14 @@ -use crate::{error_code, return_variant, CommandReturn}; +use crate::{return_variant, CommandReturn, ErrorCode}; #[test] fn failure() { - let command_return = CommandReturn { - return_variant: return_variant::FAILURE, - r1: error_code::RESERVE.into(), - r2: 1002, - r3: 1003, + let command_return = unsafe { + CommandReturn::new( + return_variant::FAILURE, + ErrorCode::Reserve as usize, + 1002, + 1003, + ) }; assert_eq!(command_return.is_failure(), true); assert_eq!(command_return.is_failure_u32(), false); @@ -18,7 +20,7 @@ assert_eq!(command_return.is_success_u64(), false); assert_eq!(command_return.is_success_3_u32(), false); assert_eq!(command_return.is_success_u32_u64(), false); - assert_eq!(command_return.get_failure(), Some(error_code::RESERVE)); + assert_eq!(command_return.get_failure(), Some(ErrorCode::Reserve)); assert_eq!(command_return.get_failure_u32(), None); assert_eq!(command_return.get_failure_2_u32(), None); assert_eq!(command_return.get_failure_u64(), None); @@ -32,11 +34,13 @@ #[test] fn failure_u32() { - let command_return = CommandReturn { - return_variant: return_variant::FAILURE_U32, - r1: error_code::OFF.into(), - r2: 1002, - r3: 1003, + let command_return = unsafe { + CommandReturn::new( + return_variant::FAILURE_U32, + ErrorCode::Off as usize, + 1002, + 1003, + ) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), true); @@ -51,7 +55,7 @@ assert_eq!(command_return.get_failure(), None); assert_eq!( command_return.get_failure_u32(), - Some((error_code::OFF, 1002)) + Some((ErrorCode::Off, 1002)) ); assert_eq!(command_return.get_failure_2_u32(), None); assert_eq!(command_return.get_failure_u64(), None); @@ -65,11 +69,13 @@ #[test] fn failure_2_u32() { - let command_return = CommandReturn { - return_variant: return_variant::FAILURE_2_U32, - r1: error_code::ALREADY.into(), - r2: 1002, - r3: 1003, + let command_return = unsafe { + CommandReturn::new( + return_variant::FAILURE_2_U32, + ErrorCode::Already as usize, + 1002, + 1003, + ) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); @@ -85,7 +91,7 @@ assert_eq!(command_return.get_failure_u32(), None); assert_eq!( command_return.get_failure_2_u32(), - Some((error_code::ALREADY, 1002, 1003)) + Some((ErrorCode::Already, 1002, 1003)) ); assert_eq!(command_return.get_failure_u64(), None); assert_eq!(command_return.get_success_u32(), None); @@ -101,11 +107,13 @@ #[test] fn failure_u64() { - let command_return = CommandReturn { - return_variant: return_variant::FAILURE_U64, - r1: error_code::BUSY.into(), - r2: 0x00001002, - r3: 0x00001003, + let command_return = unsafe { + CommandReturn::new( + return_variant::FAILURE_U64, + ErrorCode::Busy as usize, + 0x1002, + 0x1003, + ) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); @@ -122,7 +130,7 @@ assert_eq!(command_return.get_failure_2_u32(), None); assert_eq!( command_return.get_failure_u64(), - Some((error_code::BUSY, 0x00001003_00001002)) + Some((ErrorCode::Busy, 0x00001003_00001002)) ); assert_eq!(command_return.get_success_u32(), None); assert_eq!(command_return.get_success_2_u32(), None); @@ -134,12 +142,7 @@ #[test] fn success() { - let command_return = CommandReturn { - return_variant: return_variant::SUCCESS, - r1: 1001, - r2: 1002, - r3: 1003, - }; + let command_return = unsafe { CommandReturn::new(return_variant::SUCCESS, 1001, 1002, 1003) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); assert_eq!(command_return.is_failure_2_u32(), false); @@ -164,12 +167,8 @@ #[test] fn success_u32() { - let command_return = CommandReturn { - return_variant: return_variant::SUCCESS_U32, - r1: 1001, - r2: 1002, - r3: 1003, - }; + let command_return = + unsafe { CommandReturn::new(return_variant::SUCCESS_U32, 1001, 1002, 1003) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); assert_eq!(command_return.is_failure_2_u32(), false); @@ -194,12 +193,8 @@ #[test] fn success_2_u32() { - let command_return = CommandReturn { - return_variant: return_variant::SUCCESS_2_U32, - r1: 1001, - r2: 1002, - r3: 1003, - }; + let command_return = + unsafe { CommandReturn::new(return_variant::SUCCESS_2_U32, 1001, 1002, 1003) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); assert_eq!(command_return.is_failure_2_u32(), false); @@ -227,12 +222,8 @@ #[test] fn success_u64() { - let command_return = CommandReturn { - return_variant: return_variant::SUCCESS_U64, - r1: 0x00001001, - r2: 0x00001002, - r3: 1003, - }; + let command_return = + unsafe { CommandReturn::new(return_variant::SUCCESS_U64, 0x1001, 0x1002, 1003) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); assert_eq!(command_return.is_failure_2_u32(), false); @@ -257,12 +248,8 @@ #[test] fn success_3_u32() { - let command_return = CommandReturn { - return_variant: return_variant::SUCCESS_3_U32, - r1: 1001, - r2: 1002, - r3: 1003, - }; + let command_return = + unsafe { CommandReturn::new(return_variant::SUCCESS_3_U32, 1001, 1002, 1003) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); assert_eq!(command_return.is_failure_2_u32(), false); @@ -290,12 +277,8 @@ #[test] fn success_u32_u64() { - let command_return = CommandReturn { - return_variant: return_variant::SUCCESS_U32_U64, - r1: 1001, - r2: 0x00001002, - r3: 0x00001003, - }; + let command_return = + unsafe { CommandReturn::new(return_variant::SUCCESS_U32_U64, 1001, 0x1002, 0x1003) }; assert_eq!(command_return.is_failure(), false); assert_eq!(command_return.is_failure_u32(), false); assert_eq!(command_return.is_failure_2_u32(), false);
diff --git a/core/platform/src/error_code.rs b/core/platform/src/error_code.rs index 63cc34e..276e703 100644 --- a/core/platform/src/error_code.rs +++ b/core/platform/src/error_code.rs
@@ -1,39 +1,232 @@ -/// A system call error code. This can either be an error code returned by the -/// kernel or BADRVAL, which indicates the kernel returned the wrong type of -/// response to a system call. -// ErrorCode is not an enum so that conversion from the kernel's return value (a -// `usize` in a register) is free. +/// An error code returned by the kernel. // TODO: derive(Debug) is currently only enabled for test builds, which is // necessary so it can be used in assert_eq!. We should develop a lighter-weight // Debug implementation and see if it is small enough to enable on non-Debug // builds. #[cfg_attr(test, derive(Debug))] #[derive(Clone, Copy, PartialEq, Eq)] -pub struct ErrorCode(usize); +#[repr(u16)] // To facilitate use with transmute() in CommandReturn +#[rustfmt::skip] +pub enum ErrorCode { + Fail = 1, + Busy = 2, + Already = 3, + Off = 4, + Reserve = 5, + Invalid = 6, + Size = 7, + Cancel = 8, + NoMem = 9, + NoSupport = 10, + NoDevice = 11, + Uninstalled = 12, + NoAck = 13, -impl From<usize> for ErrorCode { - fn from(value: usize) -> ErrorCode { - ErrorCode(value) - } + // Error codes reserved for future use. We have to include these for future + // compatibility -- this allows process binaries compiled with this version + // of libtock-rs to run on future kernel versions that may return a larger + // variety of error codes. + N00014 = 14, N00015 = 15, + N00016 = 16, N00017 = 17, N00018 = 18, N00019 = 19, N00020 = 20, + N00021 = 21, N00022 = 22, N00023 = 23, N00024 = 24, N00025 = 25, + N00026 = 26, N00027 = 27, N00028 = 28, N00029 = 29, N00030 = 30, + N00031 = 31, N00032 = 32, N00033 = 33, N00034 = 34, N00035 = 35, + N00036 = 36, N00037 = 37, N00038 = 38, N00039 = 39, N00040 = 40, + N00041 = 41, N00042 = 42, N00043 = 43, N00044 = 44, N00045 = 45, + N00046 = 46, N00047 = 47, N00048 = 48, N00049 = 49, N00050 = 50, + N00051 = 51, N00052 = 52, N00053 = 53, N00054 = 54, N00055 = 55, + N00056 = 56, N00057 = 57, N00058 = 58, N00059 = 59, N00060 = 60, + N00061 = 61, N00062 = 62, N00063 = 63, N00064 = 64, N00065 = 65, + N00066 = 66, N00067 = 67, N00068 = 68, N00069 = 69, N00070 = 70, + N00071 = 71, N00072 = 72, N00073 = 73, N00074 = 74, N00075 = 75, + N00076 = 76, N00077 = 77, N00078 = 78, N00079 = 79, N00080 = 80, + N00081 = 81, N00082 = 82, N00083 = 83, N00084 = 84, N00085 = 85, + N00086 = 86, N00087 = 87, N00088 = 88, N00089 = 89, N00090 = 90, + N00091 = 91, N00092 = 92, N00093 = 93, N00094 = 94, N00095 = 95, + N00096 = 96, N00097 = 97, N00098 = 98, N00099 = 99, N00100 = 100, + N00101 = 101, N00102 = 102, N00103 = 103, N00104 = 104, N00105 = 105, + N00106 = 106, N00107 = 107, N00108 = 108, N00109 = 109, N00110 = 110, + N00111 = 111, N00112 = 112, N00113 = 113, N00114 = 114, N00115 = 115, + N00116 = 116, N00117 = 117, N00118 = 118, N00119 = 119, N00120 = 120, + N00121 = 121, N00122 = 122, N00123 = 123, N00124 = 124, N00125 = 125, + N00126 = 126, N00127 = 127, N00128 = 128, N00129 = 129, N00130 = 130, + N00131 = 131, N00132 = 132, N00133 = 133, N00134 = 134, N00135 = 135, + N00136 = 136, N00137 = 137, N00138 = 138, N00139 = 139, N00140 = 140, + N00141 = 141, N00142 = 142, N00143 = 143, N00144 = 144, N00145 = 145, + N00146 = 146, N00147 = 147, N00148 = 148, N00149 = 149, N00150 = 150, + N00151 = 151, N00152 = 152, N00153 = 153, N00154 = 154, N00155 = 155, + N00156 = 156, N00157 = 157, N00158 = 158, N00159 = 159, N00160 = 160, + N00161 = 161, N00162 = 162, N00163 = 163, N00164 = 164, N00165 = 165, + N00166 = 166, N00167 = 167, N00168 = 168, N00169 = 169, N00170 = 170, + N00171 = 171, N00172 = 172, N00173 = 173, N00174 = 174, N00175 = 175, + N00176 = 176, N00177 = 177, N00178 = 178, N00179 = 179, N00180 = 180, + N00181 = 181, N00182 = 182, N00183 = 183, N00184 = 184, N00185 = 185, + N00186 = 186, N00187 = 187, N00188 = 188, N00189 = 189, N00190 = 190, + N00191 = 191, N00192 = 192, N00193 = 193, N00194 = 194, N00195 = 195, + N00196 = 196, N00197 = 197, N00198 = 198, N00199 = 199, N00200 = 200, + N00201 = 201, N00202 = 202, N00203 = 203, N00204 = 204, N00205 = 205, + N00206 = 206, N00207 = 207, N00208 = 208, N00209 = 209, N00210 = 210, + N00211 = 211, N00212 = 212, N00213 = 213, N00214 = 214, N00215 = 215, + N00216 = 216, N00217 = 217, N00218 = 218, N00219 = 219, N00220 = 220, + N00221 = 221, N00222 = 222, N00223 = 223, N00224 = 224, N00225 = 225, + N00226 = 226, N00227 = 227, N00228 = 228, N00229 = 229, N00230 = 230, + N00231 = 231, N00232 = 232, N00233 = 233, N00234 = 234, N00235 = 235, + N00236 = 236, N00237 = 237, N00238 = 238, N00239 = 239, N00240 = 240, + N00241 = 241, N00242 = 242, N00243 = 243, N00244 = 244, N00245 = 245, + N00246 = 246, N00247 = 247, N00248 = 248, N00249 = 249, N00250 = 250, + N00251 = 251, N00252 = 252, N00253 = 253, N00254 = 254, N00255 = 255, + N00256 = 256, N00257 = 257, N00258 = 258, N00259 = 259, N00260 = 260, + N00261 = 261, N00262 = 262, N00263 = 263, N00264 = 264, N00265 = 265, + N00266 = 266, N00267 = 267, N00268 = 268, N00269 = 269, N00270 = 270, + N00271 = 271, N00272 = 272, N00273 = 273, N00274 = 274, N00275 = 275, + N00276 = 276, N00277 = 277, N00278 = 278, N00279 = 279, N00280 = 280, + N00281 = 281, N00282 = 282, N00283 = 283, N00284 = 284, N00285 = 285, + N00286 = 286, N00287 = 287, N00288 = 288, N00289 = 289, N00290 = 290, + N00291 = 291, N00292 = 292, N00293 = 293, N00294 = 294, N00295 = 295, + N00296 = 296, N00297 = 297, N00298 = 298, N00299 = 299, N00300 = 300, + N00301 = 301, N00302 = 302, N00303 = 303, N00304 = 304, N00305 = 305, + N00306 = 306, N00307 = 307, N00308 = 308, N00309 = 309, N00310 = 310, + N00311 = 311, N00312 = 312, N00313 = 313, N00314 = 314, N00315 = 315, + N00316 = 316, N00317 = 317, N00318 = 318, N00319 = 319, N00320 = 320, + N00321 = 321, N00322 = 322, N00323 = 323, N00324 = 324, N00325 = 325, + N00326 = 326, N00327 = 327, N00328 = 328, N00329 = 329, N00330 = 330, + N00331 = 331, N00332 = 332, N00333 = 333, N00334 = 334, N00335 = 335, + N00336 = 336, N00337 = 337, N00338 = 338, N00339 = 339, N00340 = 340, + N00341 = 341, N00342 = 342, N00343 = 343, N00344 = 344, N00345 = 345, + N00346 = 346, N00347 = 347, N00348 = 348, N00349 = 349, N00350 = 350, + N00351 = 351, N00352 = 352, N00353 = 353, N00354 = 354, N00355 = 355, + N00356 = 356, N00357 = 357, N00358 = 358, N00359 = 359, N00360 = 360, + N00361 = 361, N00362 = 362, N00363 = 363, N00364 = 364, N00365 = 365, + N00366 = 366, N00367 = 367, N00368 = 368, N00369 = 369, N00370 = 370, + N00371 = 371, N00372 = 372, N00373 = 373, N00374 = 374, N00375 = 375, + N00376 = 376, N00377 = 377, N00378 = 378, N00379 = 379, N00380 = 380, + N00381 = 381, N00382 = 382, N00383 = 383, N00384 = 384, N00385 = 385, + N00386 = 386, N00387 = 387, N00388 = 388, N00389 = 389, N00390 = 390, + N00391 = 391, N00392 = 392, N00393 = 393, N00394 = 394, N00395 = 395, + N00396 = 396, N00397 = 397, N00398 = 398, N00399 = 399, N00400 = 400, + N00401 = 401, N00402 = 402, N00403 = 403, N00404 = 404, N00405 = 405, + N00406 = 406, N00407 = 407, N00408 = 408, N00409 = 409, N00410 = 410, + N00411 = 411, N00412 = 412, N00413 = 413, N00414 = 414, N00415 = 415, + N00416 = 416, N00417 = 417, N00418 = 418, N00419 = 419, N00420 = 420, + N00421 = 421, N00422 = 422, N00423 = 423, N00424 = 424, N00425 = 425, + N00426 = 426, N00427 = 427, N00428 = 428, N00429 = 429, N00430 = 430, + N00431 = 431, N00432 = 432, N00433 = 433, N00434 = 434, N00435 = 435, + N00436 = 436, N00437 = 437, N00438 = 438, N00439 = 439, N00440 = 440, + N00441 = 441, N00442 = 442, N00443 = 443, N00444 = 444, N00445 = 445, + N00446 = 446, N00447 = 447, N00448 = 448, N00449 = 449, N00450 = 450, + N00451 = 451, N00452 = 452, N00453 = 453, N00454 = 454, N00455 = 455, + N00456 = 456, N00457 = 457, N00458 = 458, N00459 = 459, N00460 = 460, + N00461 = 461, N00462 = 462, N00463 = 463, N00464 = 464, N00465 = 465, + N00466 = 466, N00467 = 467, N00468 = 468, N00469 = 469, N00470 = 470, + N00471 = 471, N00472 = 472, N00473 = 473, N00474 = 474, N00475 = 475, + N00476 = 476, N00477 = 477, N00478 = 478, N00479 = 479, N00480 = 480, + N00481 = 481, N00482 = 482, N00483 = 483, N00484 = 484, N00485 = 485, + N00486 = 486, N00487 = 487, N00488 = 488, N00489 = 489, N00490 = 490, + N00491 = 491, N00492 = 492, N00493 = 493, N00494 = 494, N00495 = 495, + N00496 = 496, N00497 = 497, N00498 = 498, N00499 = 499, N00500 = 500, + N00501 = 501, N00502 = 502, N00503 = 503, N00504 = 504, N00505 = 505, + N00506 = 506, N00507 = 507, N00508 = 508, N00509 = 509, N00510 = 510, + N00511 = 511, N00512 = 512, N00513 = 513, N00514 = 514, N00515 = 515, + N00516 = 516, N00517 = 517, N00518 = 518, N00519 = 519, N00520 = 520, + N00521 = 521, N00522 = 522, N00523 = 523, N00524 = 524, N00525 = 525, + N00526 = 526, N00527 = 527, N00528 = 528, N00529 = 529, N00530 = 530, + N00531 = 531, N00532 = 532, N00533 = 533, N00534 = 534, N00535 = 535, + N00536 = 536, N00537 = 537, N00538 = 538, N00539 = 539, N00540 = 540, + N00541 = 541, N00542 = 542, N00543 = 543, N00544 = 544, N00545 = 545, + N00546 = 546, N00547 = 547, N00548 = 548, N00549 = 549, N00550 = 550, + N00551 = 551, N00552 = 552, N00553 = 553, N00554 = 554, N00555 = 555, + N00556 = 556, N00557 = 557, N00558 = 558, N00559 = 559, N00560 = 560, + N00561 = 561, N00562 = 562, N00563 = 563, N00564 = 564, N00565 = 565, + N00566 = 566, N00567 = 567, N00568 = 568, N00569 = 569, N00570 = 570, + N00571 = 571, N00572 = 572, N00573 = 573, N00574 = 574, N00575 = 575, + N00576 = 576, N00577 = 577, N00578 = 578, N00579 = 579, N00580 = 580, + N00581 = 581, N00582 = 582, N00583 = 583, N00584 = 584, N00585 = 585, + N00586 = 586, N00587 = 587, N00588 = 588, N00589 = 589, N00590 = 590, + N00591 = 591, N00592 = 592, N00593 = 593, N00594 = 594, N00595 = 595, + N00596 = 596, N00597 = 597, N00598 = 598, N00599 = 599, N00600 = 600, + N00601 = 601, N00602 = 602, N00603 = 603, N00604 = 604, N00605 = 605, + N00606 = 606, N00607 = 607, N00608 = 608, N00609 = 609, N00610 = 610, + N00611 = 611, N00612 = 612, N00613 = 613, N00614 = 614, N00615 = 615, + N00616 = 616, N00617 = 617, N00618 = 618, N00619 = 619, N00620 = 620, + N00621 = 621, N00622 = 622, N00623 = 623, N00624 = 624, N00625 = 625, + N00626 = 626, N00627 = 627, N00628 = 628, N00629 = 629, N00630 = 630, + N00631 = 631, N00632 = 632, N00633 = 633, N00634 = 634, N00635 = 635, + N00636 = 636, N00637 = 637, N00638 = 638, N00639 = 639, N00640 = 640, + N00641 = 641, N00642 = 642, N00643 = 643, N00644 = 644, N00645 = 645, + N00646 = 646, N00647 = 647, N00648 = 648, N00649 = 649, N00650 = 650, + N00651 = 651, N00652 = 652, N00653 = 653, N00654 = 654, N00655 = 655, + N00656 = 656, N00657 = 657, N00658 = 658, N00659 = 659, N00660 = 660, + N00661 = 661, N00662 = 662, N00663 = 663, N00664 = 664, N00665 = 665, + N00666 = 666, N00667 = 667, N00668 = 668, N00669 = 669, N00670 = 670, + N00671 = 671, N00672 = 672, N00673 = 673, N00674 = 674, N00675 = 675, + N00676 = 676, N00677 = 677, N00678 = 678, N00679 = 679, N00680 = 680, + N00681 = 681, N00682 = 682, N00683 = 683, N00684 = 684, N00685 = 685, + N00686 = 686, N00687 = 687, N00688 = 688, N00689 = 689, N00690 = 690, + N00691 = 691, N00692 = 692, N00693 = 693, N00694 = 694, N00695 = 695, + N00696 = 696, N00697 = 697, N00698 = 698, N00699 = 699, N00700 = 700, + N00701 = 701, N00702 = 702, N00703 = 703, N00704 = 704, N00705 = 705, + N00706 = 706, N00707 = 707, N00708 = 708, N00709 = 709, N00710 = 710, + N00711 = 711, N00712 = 712, N00713 = 713, N00714 = 714, N00715 = 715, + N00716 = 716, N00717 = 717, N00718 = 718, N00719 = 719, N00720 = 720, + N00721 = 721, N00722 = 722, N00723 = 723, N00724 = 724, N00725 = 725, + N00726 = 726, N00727 = 727, N00728 = 728, N00729 = 729, N00730 = 730, + N00731 = 731, N00732 = 732, N00733 = 733, N00734 = 734, N00735 = 735, + N00736 = 736, N00737 = 737, N00738 = 738, N00739 = 739, N00740 = 740, + N00741 = 741, N00742 = 742, N00743 = 743, N00744 = 744, N00745 = 745, + N00746 = 746, N00747 = 747, N00748 = 748, N00749 = 749, N00750 = 750, + N00751 = 751, N00752 = 752, N00753 = 753, N00754 = 754, N00755 = 755, + N00756 = 756, N00757 = 757, N00758 = 758, N00759 = 759, N00760 = 760, + N00761 = 761, N00762 = 762, N00763 = 763, N00764 = 764, N00765 = 765, + N00766 = 766, N00767 = 767, N00768 = 768, N00769 = 769, N00770 = 770, + N00771 = 771, N00772 = 772, N00773 = 773, N00774 = 774, N00775 = 775, + N00776 = 776, N00777 = 777, N00778 = 778, N00779 = 779, N00780 = 780, + N00781 = 781, N00782 = 782, N00783 = 783, N00784 = 784, N00785 = 785, + N00786 = 786, N00787 = 787, N00788 = 788, N00789 = 789, N00790 = 790, + N00791 = 791, N00792 = 792, N00793 = 793, N00794 = 794, N00795 = 795, + N00796 = 796, N00797 = 797, N00798 = 798, N00799 = 799, N00800 = 800, + N00801 = 801, N00802 = 802, N00803 = 803, N00804 = 804, N00805 = 805, + N00806 = 806, N00807 = 807, N00808 = 808, N00809 = 809, N00810 = 810, + N00811 = 811, N00812 = 812, N00813 = 813, N00814 = 814, N00815 = 815, + N00816 = 816, N00817 = 817, N00818 = 818, N00819 = 819, N00820 = 820, + N00821 = 821, N00822 = 822, N00823 = 823, N00824 = 824, N00825 = 825, + N00826 = 826, N00827 = 827, N00828 = 828, N00829 = 829, N00830 = 830, + N00831 = 831, N00832 = 832, N00833 = 833, N00834 = 834, N00835 = 835, + N00836 = 836, N00837 = 837, N00838 = 838, N00839 = 839, N00840 = 840, + N00841 = 841, N00842 = 842, N00843 = 843, N00844 = 844, N00845 = 845, + N00846 = 846, N00847 = 847, N00848 = 848, N00849 = 849, N00850 = 850, + N00851 = 851, N00852 = 852, N00853 = 853, N00854 = 854, N00855 = 855, + N00856 = 856, N00857 = 857, N00858 = 858, N00859 = 859, N00860 = 860, + N00861 = 861, N00862 = 862, N00863 = 863, N00864 = 864, N00865 = 865, + N00866 = 866, N00867 = 867, N00868 = 868, N00869 = 869, N00870 = 870, + N00871 = 871, N00872 = 872, N00873 = 873, N00874 = 874, N00875 = 875, + N00876 = 876, N00877 = 877, N00878 = 878, N00879 = 879, N00880 = 880, + N00881 = 881, N00882 = 882, N00883 = 883, N00884 = 884, N00885 = 885, + N00886 = 886, N00887 = 887, N00888 = 888, N00889 = 889, N00890 = 890, + N00891 = 891, N00892 = 892, N00893 = 893, N00894 = 894, N00895 = 895, + N00896 = 896, N00897 = 897, N00898 = 898, N00899 = 899, N00900 = 900, + N00901 = 901, N00902 = 902, N00903 = 903, N00904 = 904, N00905 = 905, + N00906 = 906, N00907 = 907, N00908 = 908, N00909 = 909, N00910 = 910, + N00911 = 911, N00912 = 912, N00913 = 913, N00914 = 914, N00915 = 915, + N00916 = 916, N00917 = 917, N00918 = 918, N00919 = 919, N00920 = 920, + N00921 = 921, N00922 = 922, N00923 = 923, N00924 = 924, N00925 = 925, + N00926 = 926, N00927 = 927, N00928 = 928, N00929 = 929, N00930 = 930, + N00931 = 931, N00932 = 932, N00933 = 933, N00934 = 934, N00935 = 935, + N00936 = 936, N00937 = 937, N00938 = 938, N00939 = 939, N00940 = 940, + N00941 = 941, N00942 = 942, N00943 = 943, N00944 = 944, N00945 = 945, + N00946 = 946, N00947 = 947, N00948 = 948, N00949 = 949, N00950 = 950, + N00951 = 951, N00952 = 952, N00953 = 953, N00954 = 954, N00955 = 955, + N00956 = 956, N00957 = 957, N00958 = 958, N00959 = 959, N00960 = 960, + N00961 = 961, N00962 = 962, N00963 = 963, N00964 = 964, N00965 = 965, + N00966 = 966, N00967 = 967, N00968 = 968, N00969 = 969, N00970 = 970, + N00971 = 971, N00972 = 972, N00973 = 973, N00974 = 974, N00975 = 975, + N00976 = 976, N00977 = 977, N00978 = 978, N00979 = 979, N00980 = 980, + N00981 = 981, N00982 = 982, N00983 = 983, N00984 = 984, N00985 = 985, + N00986 = 986, N00987 = 987, N00988 = 988, N00989 = 989, N00990 = 990, + N00991 = 991, N00992 = 992, N00993 = 993, N00994 = 994, N00995 = 995, + N00996 = 996, N00997 = 997, N00998 = 998, N00999 = 999, N01000 = 1000, + N01001 = 1001, N01002 = 1002, N01003 = 1003, N01004 = 1004, N01005 = 1005, + N01006 = 1006, N01007 = 1007, N01008 = 1008, N01009 = 1009, N01010 = 1010, + N01011 = 1011, N01012 = 1012, N01013 = 1013, N01014 = 1014, N01015 = 1015, + N01016 = 1016, N01017 = 1017, N01018 = 1018, N01019 = 1019, N01020 = 1020, + N01021 = 1021, N01022 = 1022, N01023 = 1023, } - -impl From<ErrorCode> for usize { - fn from(error_code: ErrorCode) -> usize { - error_code.0 - } -} - -pub const FAIL: ErrorCode = ErrorCode(1); -pub const BUSY: ErrorCode = ErrorCode(2); -pub const ALREADY: ErrorCode = ErrorCode(3); -pub const OFF: ErrorCode = ErrorCode(4); -pub const RESERVE: ErrorCode = ErrorCode(5); -pub const INVALID: ErrorCode = ErrorCode(6); -pub const SIZE: ErrorCode = ErrorCode(7); -pub const CANCEL: ErrorCode = ErrorCode(8); -pub const NOMEM: ErrorCode = ErrorCode(9); -pub const NOSUPPORT: ErrorCode = ErrorCode(10); -pub const NODEVICE: ErrorCode = ErrorCode(11); -pub const UNINSTALLED: ErrorCode = ErrorCode(12); -pub const NOACK: ErrorCode = ErrorCode(13); -pub const BADRVAL: ErrorCode = ErrorCode(1024);
diff --git a/core/platform/src/lib.rs b/core/platform/src/lib.rs index 45021ca..d57644b 100644 --- a/core/platform/src/lib.rs +++ b/core/platform/src/lib.rs
@@ -2,7 +2,7 @@ mod async_traits; mod command_return; -pub mod error_code; +mod error_code; mod raw_syscalls; pub mod return_variant; mod syscalls;
diff --git a/core/runtime/asm/asm_riscv32.S b/core/runtime/asm/asm_riscv32.S new file mode 100644 index 0000000..db1036e --- /dev/null +++ b/core/runtime/asm/asm_riscv32.S
@@ -0,0 +1,86 @@ +/* rt_header is defined by the general linker script (libtock_layout.ld). It has + * the following layout: + * + * Field | Offset + * ------------------------------------ + * Address of the start symbol | 0 + * Initial process break | 4 + * Top of the stack | 8 + * Size of .data | 12 + * Start of .data in flash | 16 + * Start of .data in ram | 20 + * Size of .bss | 24 + * Start of .bss in ram | 28 + */ + +/* start is the entry point -- the first code executed by the kernel. The kernel + * passes arguments through 4 registers: + * + * a0 Pointer to beginning of the process binary's code. The linker script + * locates rt_header at this address. + * + * a1 Address of the beginning of the process's usable memory region. + * a2 Size of the process' allocated memory region (including grant region) + * a3 Process break provided by the kernel. + * + * We currently only use the value in a0. It is copied into a5 early on because + * a0-a4 are needed to invoke system calls. + */ +.section .start, "ax" +.globl start +start: + /* First, verify the process binary was loaded at the correct address. The + * check is performed by comparing the program counter at the start to the + * address of `start`, which is stored in rt_header. */ + auipc s0, 0 /* s0 = pc */ + mv a5, a0 /* Save rt_header so syscalls don't overwrite it */ + lw s1, 0(a5) /* s1 = rt_header.start */ + beq s0, s1, .Lset_brk /* Skip error handling code if pc is correct */ + /* If the beq on the previous line did not jump, then the binary is not at + * the correct location. Report the error via LowLevelDebug then exit. */ + li a0, 8 /* LowLevelDebug driver number */ + li a1, 1 /* Command: Print alert code */ + li a2, 2 /* Alert code 2 (incorrect location) */ + li a4, 2 /* `command` class */ + ecall + li a0, 0 /* exit-terminate */ + /* TODO: Set a completion code, once completion codes are decided */ + li a4, 6 /* `exit` class */ + ecall + +.Lset_brk: + /* memop(): set brk to rt_header's initial break value */ + li a0, 0 /* operation: set break */ + lw a1, 4(a5) /* rt_header's initial process break */ + li a4, 5 /* `memop` class */ + ecall + + /* Set the stack pointer */ + lw sp, 8(a5) /* sp = rt_header._stack_top */ + + /* Copy .data into place. */ + lw a0, 12(a5) /* remaining = rt_header.data_size */ + beqz a0, .Lzero_bss /* Jump to zero_bss if remaining is zero */ + lw a1, 16(a5) /* src = rt_header.data_flash_start */ + lw a2, 20(a5) /* dest = rt_header.data_ram_start */ +.Ldata_loop_body: + lw a3, 0(a1) /* a3 = *src */ + sw a3, 0(a2) /* *dest = a3 */ + addi a0, a0, -4 /* remaining -= 4 */ + addi a1, a1, 4 /* src += 4 */ + addi a2, a2, 4 /* dest += 4 */ + bnez a0, .Ldata_loop_body /* Iterate again if remaining != 0 */ + +.Lzero_bss: + lw a0, 24(a5) /* remaining = rt_header.bss_size */ + beqz a0, .Lcall_rust_start /* Jump to call_Main if remaining is zero */ + lw a1, 28(a5) /* dest = rt_header.bss_start */ +.Lbss_loop_body: + sb zero, 0(a1) /* *dest = zero */ + addi a0, a0, -1 /* remaining -= 1 */ + addi a1, a1, 1 /* dest += 1 */ + bnez a0, .Lbss_loop_body /* Iterate again if remaining != 0 */ + +.Lcall_rust_start: + /* Note: rust_start must be a diverging function (i.e. return `!`) */ + jal rust_start
diff --git a/core/runtime/build.rs b/core/runtime/build.rs index d0281b5..347d82c 100644 --- a/core/runtime/build.rs +++ b/core/runtime/build.rs
@@ -1,6 +1,8 @@ use std::fs::copy; use std::path::PathBuf; +mod extern_asm; + // auto_layout() identifies the correct linker scripts to use based on the // LIBTOCK_PLATFORM environment variable, and copies the linker scripts into // OUT_DIR. The cargo invocation must pass -C link-arg=-Tlayout.ld to rustc @@ -8,7 +10,7 @@ #[cfg(not(feature = "no_auto_layout"))] fn auto_layout(out_dir: &str) { const PLATFORM_CFG_VAR: &str = "LIBTOCK_PLATFORM"; - const LAYOUT_GENERIC_FILENAME: &str = "layout_generic.ld"; + const LAYOUT_GENERIC_FILENAME: &str = "libtock_layout.ld"; // Note: we need to print these rerun-if commands before using the variable // or file, so that if the build script fails cargo knows when to re-run it. @@ -49,7 +51,9 @@ #[cfg(not(feature = "no_auto_layout"))] auto_layout(out_dir); - // This link search path is used by both auto_layout() and extern_asm(). - // TODO: Add external assembly and extern_asm(). + extern_asm::build_and_link(out_dir); + + // This link search path is used by both auto_layout() and + // extern_asm::build_and_link(). println!("cargo:rustc-link-search={}", out_dir); }
diff --git a/core/runtime/extern_asm.rs b/core/runtime/extern_asm.rs new file mode 100644 index 0000000..d0488f8 --- /dev/null +++ b/core/runtime/extern_asm.rs
@@ -0,0 +1,140 @@ +//! Build script module for compiling the external assembly (used for the entry +//! point) and linking it into the process binary. Requires out_dir to be added +//! to rustc's link search path. + +pub(crate) fn build_and_link(out_dir: &str) { + use std::env::var; + let arch = var("CARGO_CFG_TARGET_ARCH").expect("Unable to read CARGO_CFG_TARGET_ARCH"); + + // Identify the toolchain configurations to try for the target architecture. + // We support trying multiple toolchains because not all toolchains are + // available on every OS that we want to support development on. + let build_configs = match arch.as_str() { + "riscv32" => &[ + // First try riscv64-unknown-elf, as it is the toolchain used by + // libtock-c and the toolchain used in the CI environment. + AsmBuildConfig { + triple: "riscv64-unknown-elf", + as_extra_args: &["-march=rv32imc"], + strip: true, + }, + // Second try riscv32-unknown-elf. This is the best match for Tock's + // risc-v targets, but is not as widely available (and has not been + // tested with libtock-rs yet). + AsmBuildConfig { + triple: "riscv32-unknown-elf", + as_extra_args: &[], + strip: false, // Untested, may need to change. + }, + // Last try riscv64-linux-gnu, as it is the only option on Debian 10 + AsmBuildConfig { + triple: "riscv64-linux-gnu", + as_extra_args: &["-march=rv32imc"], + strip: true, + }, + ], + unknown_arch => { + panic!("Unsupported architecture {}", unknown_arch); + } + }; + + // Loop through toolchain configs until one works. + for &build_config in build_configs { + if try_build(&arch, build_config, out_dir).is_ok() { + return; + } + } +} + +#[derive(Clone, Copy)] +struct AsmBuildConfig { + // Triple name, which is prepended to the command names. + triple: &'static str, + + // Extra arguments to pass to the assembler. + as_extra_args: &'static [&'static str], + + // Do we need to strip the object file before packing it into the library + // archive? This should be set to true on platforms where the assembler adds + // local symbols to the object file. + strip: bool, +} + +// Indicates the toolchain in the build config is unavailable. +struct ToolchainUnavailable; + +fn try_build( + arch: &str, + build_config: AsmBuildConfig, + out_dir: &str, +) -> Result<(), ToolchainUnavailable> { + use std::path::PathBuf; + use std::process::Command; + + // Invoke the assembler to produce an object file. + let asm_source = &format!("asm/asm_{}.S", arch); + let obj_file_path = [out_dir, "libtock_rt_asm.o"].iter().collect::<PathBuf>(); + let obj_file = obj_file_path.to_str().expect("Non-Unicode obj_file_path"); + let as_result = Command::new(format!("{}-as", build_config.triple)) + .args(build_config.as_extra_args) + .args(&[asm_source, "-o", obj_file]) + .status(); + + match as_result { + Err(error) => { + if error.kind() == std::io::ErrorKind::NotFound { + // This `as` command does not exist. Return an error so + // build_an_link can try another config (if one is available). + return Err(ToolchainUnavailable); + } else { + panic!("Error invoking assembler: {}", error); + } + } + Ok(status) => { + assert!(status.success(), "Assembler returned an error"); + } + } + + // At this point, we know this toolchain is installed. We will fail if later + // commands are uninstalled rather than trying a different build config. + + println!("cargo:rerun-if-changed={}", asm_source); + + // Run `strip` if necessary. + if build_config.strip { + let strip_cmd = format!("{}-strip", build_config.triple); + let status = Command::new(&strip_cmd) + .args(&["-K", "start", "-K", "rust_start", obj_file]) + .status() + .unwrap_or_else(|_| panic!("Failed to invoke {}", strip_cmd)); + assert!(status.success(), "{} returned an error", strip_cmd); + } + + // Remove the archive file in case there is something unexpected in it. This + // prevents issues from persisting across invocations of this script. + const ARCHIVE_NAME: &str = "tock_rt_asm"; + let archive_path: PathBuf = [out_dir, &format!("lib{}.a", ARCHIVE_NAME)] + .iter() + .collect(); + if let Err(error) = std::fs::remove_file(&archive_path) { + if error.kind() != std::io::ErrorKind::NotFound { + panic!("Unable to remove archive file {}", archive_path.display()); + } + } + + // Create the library archive. + let ar_cmd = format!("{}-ar", build_config.triple); + let archive = archive_path.to_str().expect("Non-Unicode archive_path"); + let status = std::process::Command::new(&ar_cmd) + // c == Do not complain if archive needs to be created. + // r == Insert or replace file in archive. + .args(&["cr", archive, obj_file]) + .status() + .unwrap_or_else(|_| panic!("Failed to invoke {}", ar_cmd)); + assert!(status.success(), "{} returned an error", ar_cmd); + + // Tell rustc to link the binary against the library archive. + println!("cargo:rustc-link-lib=static={}", ARCHIVE_NAME); + + Ok(()) +}
diff --git a/core/runtime/layout_generic.ld b/core/runtime/layout_generic.ld deleted file mode 100644 index 0bbef87..0000000 --- a/core/runtime/layout_generic.ld +++ /dev/null
@@ -1,171 +0,0 @@ -/* Userland Generic Layout - * - * Currently, due to incomplete ROPI-RWPI support in rustc (see - * https://github.com/tock/libtock-rs/issues/28), this layout implements static - * linking. An application init script must define the FLASH and SRAM address - * ranges as well as MPU_MIN_ALIGN before including this layout file. - * - * Here is a an example application linker script to get started: - * MEMORY { - * /* FLASH memory region must start immediately *after* the Tock - * * Binary Format headers, which means you need to offset the - * * beginning of FLASH memory region relative to where the - * * application is loaded. - * FLASH (rx) : ORIGIN = 0x10030, LENGTH = 0x0FFD0 - * SRAM (RWX) : ORIGIN = 0x20000, LENGTH = 0x10000 - * } - * MPU_MIN_ALIGN = 8K; - * INCLUDE ../libtock-rs/layout.ld - */ - -ENTRY(_start) - -SECTIONS { - /* Section for just the app crt0 header. - * This must be first so that the app can find it. - */ - .crt0_header : - { - _beginning = .; /* Start of the app in flash. */ - /** - * Populate the header expected by `crt0`: - * - * struct hdr { - * uint32_t got_sym_start; - * uint32_t got_start; - * uint32_t got_size; - * uint32_t data_sym_start; - * uint32_t data_start; - * uint32_t data_size; - * uint32_t bss_start; - * uint32_t bss_size; - * uint32_t reldata_start; - * uint32_t stack_size; - * }; - */ - /* Offset of GOT symbols in flash */ - LONG(LOADADDR(.got) - _beginning); - /* Offset of GOT section in memory */ - LONG(_got); - /* Size of GOT section */ - LONG(SIZEOF(.got)); - /* Offset of data symbols in flash */ - LONG(LOADADDR(.data) - _beginning); - /* Offset of data section in memory */ - LONG(_data); - /* Size of data section */ - LONG(SIZEOF(.data)); - /* Offset of BSS section in memory */ - LONG(_bss); - /* Size of BSS section */ - LONG(SIZEOF(.bss)); - /* First address offset after program flash, where elf2tab places - * .rel.data section */ - LONG(LOADADDR(.endflash) - _beginning); - /* The size of the stack requested by this application */ - LONG(_stack_top_aligned - _sstack); - /* Pad the header out to a multiple of 32 bytes so there is not a gap - * between the header and subsequent .data section. It's unclear why, - * but LLD is aligning sections to a multiple of 32 bytes. */ - . = ALIGN(32); - } > FLASH =0xFF - - /* Text section, Code! */ - .text : - { - . = ALIGN(4); - _text = .; - KEEP (*(.start)) - *(.text*) - *(.rodata*) - KEEP (*(.syscalls)) - *(.ARM.extab*) - . = ALIGN(4); /* Make sure we're word-aligned here */ - _etext = .; - } > FLASH =0xFF - - /* Application stack */ - .stack (NOLOAD) : - { - /* elf2tab requires that the `_sram_origin` symbol be present to - * mark the first address in the SRAM memory. Since ELF files do - * not really need to specify this address as they only care about - * loading into flash, we need to manually mark this address for - * elf2tab. elf2tab will use it to add a fixed address header in the - * TBF header if needed. - */ - _sram_origin = .; - _sstack = .; - KEEP(*(.stack_buffer)) - _stack_top_unaligned = .; - . = ALIGN(8); - _stack_top_aligned = .; - } > SRAM - - /* Data section, static initialized variables - * Note: This is placed in Flash after the text section, but needs to be - * moved to SRAM at runtime - */ - .data : AT (_etext) - { - . = ALIGN(4); /* Make sure we're word-aligned here */ - _data = .; - KEEP(*(.data*)) - *(.sdata*) /* RISC-V small-pointer data section */ - . = ALIGN(4); /* Make sure we're word-aligned at the end of flash */ - } > SRAM - - /* Global Offset Table */ - .got : - { - . = ALIGN(4); /* Make sure we're word-aligned here */ - _got = .; - *(.got*) - *(.got.plt*) - . = ALIGN(4); - } > SRAM - - /* BSS section, static uninitialized variables */ - .bss : - { - . = ALIGN(4); /* Make sure we're word-aligned here */ - _bss = .; - KEEP(*(.bss* .sbss*)) - *(COMMON) - . = ALIGN(4); - } > SRAM - - /* End of flash. */ - .endflash : - { - } > FLASH - - /* ARM Exception support - * - * This contains compiler-generated support for unwinding the stack, - * consisting of key-value pairs of function addresses and information on - * how to unwind stack frames. - * https://wiki.linaro.org/KenWerner/Sandbox/libunwind?action=AttachFile&do=get&target=libunwind-LDS.pdf - * - * .ARM.exidx is sorted, so has to go in its own output section. - * - * __NOTE__: It's at the end because we currently don't actually serialize - * it to the binary in elf2tbf. If it was before the RAM sections, it would - * through off our calculations of the header. - */ - PROVIDE_HIDDEN (__exidx_start = .); - .ARM.exidx : - { - /* (C++) Index entries for section unwinding */ - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - PROVIDE_HIDDEN (__exidx_end = .); - - /DISCARD/ : - { - *(.eh_frame) - } -} - -ASSERT((_stack_top_aligned - _stack_top_unaligned) == 0, " -STACK_SIZE must be 8 byte multiple")
diff --git a/core/runtime/layouts/apollo3.ld b/core/runtime/layouts/apollo3.ld index 8713c27..464cf98 100644 --- a/core/runtime/layouts/apollo3.ld +++ b/core/runtime/layouts/apollo3.ld
@@ -1,11 +1,9 @@ /* Layout for the Apollo3 MCU, used by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x00040040, LENGTH = 0x0005FFC0 - SRAM (rwx) : ORIGIN = 0x10002000, LENGTH = 0x2000 + FLASH (X) : ORIGIN = 0x00040000, LENGTH = 0x00060000 + RAM (W) : ORIGIN = 0x10002000, LENGTH = 0x2000 } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/hail.ld b/core/runtime/layouts/hail.ld index 179a883..db48142 100644 --- a/core/runtime/layouts/hail.ld +++ b/core/runtime/layouts/hail.ld
@@ -1,11 +1,9 @@ /* Layout for the Hail board, used by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x00030040, LENGTH = 0x0005FFC0 - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K + FLASH (X) : ORIGIN = 0x00030000, LENGTH = 0x00060000 + RAM (W) : ORIGIN = 0x20004000, LENGTH = 62K } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/hifive1.ld b/core/runtime/layouts/hifive1.ld index 20294ce..78dc51b 100644 --- a/core/runtime/layouts/hifive1.ld +++ b/core/runtime/layouts/hifive1.ld
@@ -1,18 +1,12 @@ /* Layout for the RISC-V 32 boards, used by the examples in this repository. */ MEMORY { - /* - * The TBF header can change in size so use 0x40 combined with - * --protected-region-size with elf2tab to cover a header upto that - * size. - * - * Note that the SRAM address may need to be changed depending on + /* Note that the SRAM address may need to be changed depending on * the kernel binary, check for the actual address of APP_MEMORY! */ - FLASH (rx) : ORIGIN = 0x20040040, LENGTH = 32M - SRAM (rwx) : ORIGIN = 0x80002400, LENGTH = 0x1C00 + FLASH (X) : ORIGIN = 0x20040000, LENGTH = 32M + RAM (W) : ORIGIN = 0x80002400, LENGTH = 0x1C00 } -MPU_MIN_ALIGN = 1K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/imxrt1050.ld b/core/runtime/layouts/imxrt1050.ld index 3e7f904..1458870 100644 --- a/core/runtime/layouts/imxrt1050.ld +++ b/core/runtime/layouts/imxrt1050.ld
@@ -1,11 +1,9 @@ /* Layout for the iMX.RT1050 board, used by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x63002040, LENGTH = 0xFFFFC0 - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 112K + FLASH (X) : ORIGIN = 0x63002000, LENGTH = 0x1000000 + RAM (W) : ORIGIN = 0x20004000, LENGTH = 112K } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/msp432.ld b/core/runtime/layouts/msp432.ld index 2c9d2a4..170d4b1 100644 --- a/core/runtime/layouts/msp432.ld +++ b/core/runtime/layouts/msp432.ld
@@ -1,9 +1,7 @@ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x00020040, LENGTH = 0x0001FFC0 - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 0x2000 + FLASH (X) : ORIGIN = 0x00020000, LENGTH = 0x00020000 + RAM (W) : ORIGIN = 0x20004000, LENGTH = 0x2000 } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/nrf52.ld b/core/runtime/layouts/nrf52.ld index 942e86b..fbbcdc3 100644 --- a/core/runtime/layouts/nrf52.ld +++ b/core/runtime/layouts/nrf52.ld
@@ -1,11 +1,9 @@ /* Layout for the nRF52-DK, used by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x00030040, LENGTH = 0x0005FFC0 - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K + FLASH (X) : ORIGIN = 0x00030000, LENGTH = 0x00060000 + RAM (W) : ORIGIN = 0x20004000, LENGTH = 62K } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/nrf52840.ld b/core/runtime/layouts/nrf52840.ld index 31bf346..06b6f6b 100644 --- a/core/runtime/layouts/nrf52840.ld +++ b/core/runtime/layouts/nrf52840.ld
@@ -1,11 +1,9 @@ /* Layout for the nRF52840-DK, usable by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x00030040, LENGTH = 0x000CFFC0 - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K + FLASH (X) : ORIGIN = 0x00030000, LENGTH = 0x000D0000 + RAM (W) : ORIGIN = 0x20004000, LENGTH = 62K } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/nucleo_f429zi.ld b/core/runtime/layouts/nucleo_f429zi.ld index 3e407b4..a9c634a 100644 --- a/core/runtime/layouts/nucleo_f429zi.ld +++ b/core/runtime/layouts/nucleo_f429zi.ld
@@ -1,11 +1,9 @@ /* Layout for the Nucleo F429zi, used by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x08040040, LENGTH = 255K - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 112K + FLASH (X) : ORIGIN = 0x08040000, LENGTH = 255K + RAM (W) : ORIGIN = 0x20004000, LENGTH = 112K } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/nucleo_f446re.ld b/core/runtime/layouts/nucleo_f446re.ld index 83e698b..d3953f5 100644 --- a/core/runtime/layouts/nucleo_f446re.ld +++ b/core/runtime/layouts/nucleo_f446re.ld
@@ -1,11 +1,9 @@ /* Layout for the Nucleo F446re, used by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x08040040, LENGTH = 255K - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 176K + FLASH (X) : ORIGIN = 0x08040000, LENGTH = 255K + RAM (W) : ORIGIN = 0x20004000, LENGTH = 176K } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/opentitan.ld b/core/runtime/layouts/opentitan.ld index ada781c..50ea340 100644 --- a/core/runtime/layouts/opentitan.ld +++ b/core/runtime/layouts/opentitan.ld
@@ -1,18 +1,12 @@ /* Layout for the RISC-V 32 boards, used by the examples in this repository. */ MEMORY { - /* - * The TBF header can change in size so use 0x40 combined with - * --protected-region-size with elf2tab to cover a header upto that - * size. - * - * Note that the SRAM address may need to be changed depending on + /* Note that the SRAM address may need to be changed depending on * the kernel binary, check for the actual address of APP_MEMORY! */ - FLASH (rx) : ORIGIN = 0x20030040, LENGTH = 32M - SRAM (rwx) : ORIGIN = 0x10004000, LENGTH = 512K + FLASH (X) : ORIGIN = 0x20030000, LENGTH = 32M + RAM (W) : ORIGIN = 0x10004000, LENGTH = 512K } -MPU_MIN_ALIGN = 1K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/layouts/stm32f3discovery.ld b/core/runtime/layouts/stm32f3discovery.ld index 9368003..05b0b54 100644 --- a/core/runtime/layouts/stm32f3discovery.ld +++ b/core/runtime/layouts/stm32f3discovery.ld
@@ -1,11 +1,9 @@ /* Layout for the stm32f3discovery board, usable by the examples in this repository. */ MEMORY { - /* The application region is 64 bytes (0x40) */ - FLASH (rx) : ORIGIN = 0x08020040, LENGTH = 0x00020000 - SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 48K + FLASH (X) : ORIGIN = 0x08020000, LENGTH = 0x00020000 + RAM (W) : ORIGIN = 0x20004000, LENGTH = 48K } -MPU_MIN_ALIGN = 8K; - -INCLUDE layout_generic.ld +TBF_HEADER_SIZE = 0x40; +INCLUDE libtock_layout.ld
diff --git a/core/runtime/libtock_layout.ld b/core/runtime/libtock_layout.ld new file mode 100644 index 0000000..fcff09a --- /dev/null +++ b/core/runtime/libtock_layout.ld
@@ -0,0 +1,129 @@ +/* Layout file for Tock process binaries that use libtock-rs. This currently + * implements static linking, because we do not have a working + * position-independent relocation solution. This layout works for all + * platforms libtock-rs supports (ARM and RISC-V). + * + * This layout should be included by a script that defines the FLASH and RAM + * regions for the board as well as TBF_HEADER_SIZE. Here is a an example + * process binary linker script to get started: + * MEMORY { + * FLASH (X) : ORIGIN = 0x10000, LENGTH = 0x10000 + * RAM (W) : ORIGIN = 0x20000, LENGTH = 0x10000 + * } + * TBF_HEADER_SIZE = 0x40; + * INCLUDE ../libtock-rs/layout.ld + * + * FLASH refers to the area the process binary occupies in flash, including TBF + * headers. RAM refers to the area the process will have access to in memory. + * STACK_SIZE is the size of the process' stack (this layout file may round the + * stack size up for alignment purposes). TBF_HEADER_SIZE must correspond to the + * --protected-region-size flag passed to elf2tab. + * + * This places the flash sections in the following order: + * 1. .rt_header -- Constants used by runtime initialization. + * 2. .text -- Executable code. + * 3. .rodata -- Read-only global data (e.g. most string constants). + * 4. .data -- Read-write data, copied to RAM at runtime. + * + * This places the RAM sections in the following order: + * 1. .stack -- The stack grows downward. Putting it first gives us + * MPU-based overflow detection. + * 2. .data -- Read-write data, initialized by copying from flash. + * 3. .bss -- Zero-initialized read-write global data. + * 4. Heap -- The heap (optional) comes after .bss and grows upwards to + * the process break. + */ + +/* TODO: Should TBF_HEADER_SIZE be configured via a similar mechanism to the + * stack size? We should see if that is possible. + */ + +/* GNU LD looks for `start` as an entry point by default, while LLVM's LLD looks + * for `_start`. To be compatible with both, we manually specify an entry point. + */ +ENTRY(start) + +SECTIONS { + /* Sections located in FLASH at runtime. + */ + + /* Add a section where elf2tab will place the TBF headers, so that the rest + * of the FLASH sections are in the right locations. */ + .tbf_header (NOLOAD) : { + . = . + TBF_HEADER_SIZE; + } > FLASH + + /* Runtime header. Contains values the linker knows that the runtime needs + * to look up. + */ + .rt_header : { + rt_header = .; + LONG(start); + LONG(ADDR(.bss) + SIZEOF(.bss)); /* Initial process break */ + LONG(_stack_top); + LONG(SIZEOF(.data)); + LONG(LOADADDR(.data)); + LONG(ADDR(.data)); + LONG(SIZEOF(.bss)); + LONG(ADDR(.bss)); + } > FLASH + + /* Text section -- the application's code. */ + .text ALIGN(4) : { + *(.start) + *(.text) + } > FLASH + + /* Read-only data section. Contains strings and other global constants. */ + .rodata ALIGN(4) : { + *(.rodata) + /* .data is placed after .rodata in flash. data_flash_start is used by + * AT() to place .data in flash as well as in rt_header. + */ + _data_flash_start = .; + } > FLASH + + /* Sections located in RAM at runtime. + */ + + /* Reserve space for the stack. Aligned to a multiple of 16 bytes for the + * RISC-V calling convention: + * https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf + */ + .stack (NOLOAD) : { + KEEP(*(.stack_buffer)) + . = ALIGN(16); + _stack_top = .; /* Used in rt_header */ + } > RAM + + /* Read-write data section. This is deployed as part of FLASH but is copied + * into RAM at runtime. + */ + .data ALIGN(4) : AT(_data_flash_start) { + data_ram_start = .; + /* .sdata is the RISC-V small data section */ + *(.sdata .data) + /* Pad to word alignment so the relocation loop can use word-sized + * copies. + */ + . = ALIGN(4); + } > RAM + + /* BSS section. These are zero-initialized static variables. This section is + * not copied from FLASH into RAM but rather directly initialized, and is + * mainly put in this linker script so that we get an error if it overflows + * the RAM region. + */ + .bss ALIGN(4) (NOLOAD) : { + /* .sbss is the RISC-V small data section */ + *(.sbss .bss) + } > RAM + + _heap_start = ADDR(.bss) + SIZEOF(.bss); /* Used by rt_header */ + + /* Sections we do not need. */ + /DISCARD/ : + { + *(.ARM.exidx .eh_frame) + } +}