├── .cargo └── config ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── app ├── .cargo │ └── config ├── .gdbinit ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── examples │ ├── arp.rs │ └── ether.rs ├── flash-example.sh ├── flash.sh ├── openocd.cfg └── src │ └── main.rs ├── arch ├── Cargo.toml └── src │ ├── lib.rs │ ├── nvic.rs │ └── systick.rs ├── devices ├── stm32f429zi │ ├── Cargo.toml │ ├── build.rs │ ├── device.ld │ └── src │ │ ├── dma.rs │ │ ├── eth.rs │ │ ├── exti.rs │ │ ├── gpio.rs │ │ ├── irq.rs │ │ ├── lib.rs │ │ ├── rcc.rs │ │ ├── serial.rs │ │ └── syscfg.rs └── wio_terminal │ ├── Cargo.toml │ ├── build.rs │ ├── device.ld │ └── src │ ├── button.rs │ ├── generic_clock.rs │ ├── irq.rs │ ├── led.rs │ ├── lib.rs │ ├── pin.rs │ └── port.rs ├── kernel ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs └── src │ ├── asm.s │ ├── interrupt_manager.rs │ ├── kernel.rs │ ├── lib.rs │ ├── macros.rs │ ├── message_manager.rs │ ├── process.rs │ ├── process_list.rs │ ├── process_manager.rs │ ├── scheduler.rs │ ├── scheduler │ └── simple_scheduler.rs │ └── syscall_id.rs ├── log ├── .gitignore ├── Cargo.toml ├── build.rs ├── log.ld └── src │ └── lib.rs ├── qemu-gnuarmeclipse.sh ├── qemu_app ├── .cargo │ └── config ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── device.ld └── src │ └── main.rs ├── rt ├── .cargo │ └── config ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── link.ld └── src │ └── lib.rs ├── rust-toolchain ├── user ├── Cargo.toml └── src │ ├── lib.rs │ ├── syscall.rs │ └── util.rs ├── util ├── .gitignore ├── Cargo.toml └── src │ ├── allocator.rs │ ├── avl_tree.rs │ ├── binary_tree.rs │ ├── lib.rs │ ├── linked_list.rs │ └── sync.rs └── wio_app ├── .cargo └── config ├── Cargo.toml ├── examples └── led.rs └── src └── main.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [target.thumbv7em-none-eabihf] 2 | 3 | [target.thumbv7m-none-eabi] 4 | 5 | [build] 6 | target = "thumbv7em-none-eabihf" 7 | 8 | [unstable] 9 | build-std = ["core", "compiler_builtins"] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aligned" 7 | version = "0.3.5" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "3a785a543aea40f5e4e2e93bb2655d31bc21bb391fff65697150973e383f16bb" 10 | dependencies = [ 11 | "as-slice", 12 | ] 13 | 14 | [[package]] 15 | name = "app" 16 | version = "0.1.0" 17 | dependencies = [ 18 | "arch", 19 | "cortex-m-semihosting", 20 | "embedded-hal", 21 | "kernel", 22 | "log", 23 | "rt", 24 | "smoltcp", 25 | "stm32f429zi", 26 | "user", 27 | "util", 28 | ] 29 | 30 | [[package]] 31 | name = "arch" 32 | version = "0.1.0" 33 | dependencies = [ 34 | "volatile-register", 35 | ] 36 | 37 | [[package]] 38 | name = "array-init" 39 | version = "2.0.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6" 42 | 43 | [[package]] 44 | name = "as-slice" 45 | version = "0.1.5" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" 48 | dependencies = [ 49 | "generic-array 0.12.4", 50 | "generic-array 0.13.3", 51 | "generic-array 0.14.4", 52 | "stable_deref_trait", 53 | ] 54 | 55 | [[package]] 56 | name = "bare-metal" 57 | version = "0.2.5" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 60 | dependencies = [ 61 | "rustc_version", 62 | ] 63 | 64 | [[package]] 65 | name = "bitfield" 66 | version = "0.13.2" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" 69 | 70 | [[package]] 71 | name = "bitflags" 72 | version = "1.3.2" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 75 | 76 | [[package]] 77 | name = "byteorder" 78 | version = "1.4.3" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 81 | 82 | [[package]] 83 | name = "cc" 84 | version = "1.0.72" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 87 | 88 | [[package]] 89 | name = "cortex-m" 90 | version = "0.7.3" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "2ac919ef424449ec8c08d515590ce15d9262c0ca5f0da5b0c901e971a3b783b3" 93 | dependencies = [ 94 | "bare-metal", 95 | "bitfield", 96 | "embedded-hal", 97 | "volatile-register", 98 | ] 99 | 100 | [[package]] 101 | name = "cortex-m-semihosting" 102 | version = "0.3.7" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc" 105 | dependencies = [ 106 | "cortex-m", 107 | ] 108 | 109 | [[package]] 110 | name = "embedded-hal" 111 | version = "0.2.6" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "e36cfb62ff156596c892272f3015ef952fe1525e85261fa3a7f327bd6b384ab9" 114 | dependencies = [ 115 | "nb 0.1.3", 116 | "void", 117 | ] 118 | 119 | [[package]] 120 | name = "fuchsia-cprng" 121 | version = "0.1.1" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 124 | 125 | [[package]] 126 | name = "generic-array" 127 | version = "0.12.4" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" 130 | dependencies = [ 131 | "typenum", 132 | ] 133 | 134 | [[package]] 135 | name = "generic-array" 136 | version = "0.13.3" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" 139 | dependencies = [ 140 | "typenum", 141 | ] 142 | 143 | [[package]] 144 | name = "generic-array" 145 | version = "0.14.4" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 148 | dependencies = [ 149 | "typenum", 150 | "version_check", 151 | ] 152 | 153 | [[package]] 154 | name = "kernel" 155 | version = "0.1.0" 156 | dependencies = [ 157 | "arch", 158 | "cc", 159 | "cortex-m-semihosting", 160 | "embedded-hal", 161 | "log", 162 | "rt", 163 | "util", 164 | ] 165 | 166 | [[package]] 167 | name = "libc" 168 | version = "0.2.108" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" 171 | 172 | [[package]] 173 | name = "lock_api" 174 | version = "0.4.5" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 177 | dependencies = [ 178 | "scopeguard", 179 | ] 180 | 181 | [[package]] 182 | name = "log" 183 | version = "0.1.0" 184 | dependencies = [ 185 | "cortex-m-semihosting", 186 | ] 187 | 188 | [[package]] 189 | name = "managed" 190 | version = "0.7.2" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577" 193 | 194 | [[package]] 195 | name = "nb" 196 | version = "0.1.3" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 199 | dependencies = [ 200 | "nb 1.0.0", 201 | ] 202 | 203 | [[package]] 204 | name = "nb" 205 | version = "1.0.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" 208 | 209 | [[package]] 210 | name = "qemu_app" 211 | version = "0.1.0" 212 | dependencies = [ 213 | "arch", 214 | "cortex-m-semihosting", 215 | "embedded-hal", 216 | "kernel", 217 | "log", 218 | "nb 0.1.3", 219 | "rt", 220 | "user", 221 | "util", 222 | ] 223 | 224 | [[package]] 225 | name = "rand" 226 | version = "0.3.23" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" 229 | dependencies = [ 230 | "libc", 231 | "rand 0.4.6", 232 | ] 233 | 234 | [[package]] 235 | name = "rand" 236 | version = "0.4.6" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 239 | dependencies = [ 240 | "fuchsia-cprng", 241 | "libc", 242 | "rand_core 0.3.1", 243 | "rdrand", 244 | "winapi", 245 | ] 246 | 247 | [[package]] 248 | name = "rand_core" 249 | version = "0.3.1" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 252 | dependencies = [ 253 | "rand_core 0.4.2", 254 | ] 255 | 256 | [[package]] 257 | name = "rand_core" 258 | version = "0.4.2" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 261 | 262 | [[package]] 263 | name = "rdrand" 264 | version = "0.4.0" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 267 | dependencies = [ 268 | "rand_core 0.3.1", 269 | ] 270 | 271 | [[package]] 272 | name = "rt" 273 | version = "0.1.0" 274 | dependencies = [ 275 | "cortex-m-semihosting", 276 | "log", 277 | ] 278 | 279 | [[package]] 280 | name = "rustc_version" 281 | version = "0.2.3" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 284 | dependencies = [ 285 | "semver", 286 | ] 287 | 288 | [[package]] 289 | name = "scopeguard" 290 | version = "1.1.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 293 | 294 | [[package]] 295 | name = "semver" 296 | version = "0.9.0" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 299 | dependencies = [ 300 | "semver-parser", 301 | ] 302 | 303 | [[package]] 304 | name = "semver-parser" 305 | version = "0.7.0" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 308 | 309 | [[package]] 310 | name = "smoltcp" 311 | version = "0.7.5" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "3e4a069bef843d170df47e7c0a8bf8d037f217d9f5b325865acc3e466ffe40d3" 314 | dependencies = [ 315 | "bitflags", 316 | "byteorder", 317 | "managed", 318 | ] 319 | 320 | [[package]] 321 | name = "stable_deref_trait" 322 | version = "1.2.0" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 325 | 326 | [[package]] 327 | name = "stm32f429zi" 328 | version = "0.1.0" 329 | dependencies = [ 330 | "aligned", 331 | "embedded-hal", 332 | "nb 0.1.3", 333 | "rt", 334 | "vcell", 335 | "volatile-register", 336 | ] 337 | 338 | [[package]] 339 | name = "typenum" 340 | version = "1.14.0" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" 343 | 344 | [[package]] 345 | name = "user" 346 | version = "0.1.0" 347 | dependencies = [ 348 | "kernel", 349 | ] 350 | 351 | [[package]] 352 | name = "util" 353 | version = "0.1.0" 354 | dependencies = [ 355 | "array-init", 356 | "lock_api", 357 | "rand 0.3.23", 358 | ] 359 | 360 | [[package]] 361 | name = "vcell" 362 | version = "0.1.3" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 365 | 366 | [[package]] 367 | name = "version_check" 368 | version = "0.9.3" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 371 | 372 | [[package]] 373 | name = "void" 374 | version = "1.0.2" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 377 | 378 | [[package]] 379 | name = "volatile-register" 380 | version = "0.2.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" 383 | dependencies = [ 384 | "vcell", 385 | ] 386 | 387 | [[package]] 388 | name = "winapi" 389 | version = "0.3.9" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 392 | dependencies = [ 393 | "winapi-i686-pc-windows-gnu", 394 | "winapi-x86_64-pc-windows-gnu", 395 | ] 396 | 397 | [[package]] 398 | name = "winapi-i686-pc-windows-gnu" 399 | version = "0.4.0" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 402 | 403 | [[package]] 404 | name = "winapi-x86_64-pc-windows-gnu" 405 | version = "0.4.0" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 408 | 409 | [[package]] 410 | name = "wio_app" 411 | version = "0.1.0" 412 | dependencies = [ 413 | "arch", 414 | "cortex-m-semihosting", 415 | "embedded-hal", 416 | "kernel", 417 | "log", 418 | "rt", 419 | "user", 420 | "util", 421 | "wio_terminal", 422 | ] 423 | 424 | [[package]] 425 | name = "wio_terminal" 426 | version = "0.1.0" 427 | dependencies = [ 428 | "volatile-register", 429 | ] 430 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "app", 4 | "arch", 5 | "devices/stm32f429zi", 6 | "devices/wio_terminal", 7 | "kernel", 8 | "log", 9 | "qemu_app", 10 | "rt", 11 | "user", 12 | "util", 13 | "wio_app", 14 | ] 15 | exclude = [".cargo"] 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ErkOS 2 | This is a prototype embedded operating system written in Rust. 3 | The target architecture is Cortex-M based board. 4 | 5 | ## Structure 6 | * `app`: An example application for Nucleo-F429ZI board 7 | * `qemu_app`: An example application for QEMU 8 | * `arch`: device drivers for ARMv7-M peripherals 9 | * `device`: device drivers for STM32F4291ZI 10 | * `kernel`: The core structs of this OS. This has dependency on `arch`, but no dependency on `device` 11 | * `log`: utility for logging (based on [The Embedonomicon](https://docs.rust-embedded.org/embedonomicon/logging.html) example code) 12 | * `rt`: runtime for ARMv7-M baremetal environment 13 | * `util`: utilities independent from architecture 14 | 15 | ## Reference 16 | * [The Embedonomicon](https://docs.rust-embedded.org/embedonomicon/) 17 | * [Tock](https://www.tockos.org/) 18 | -------------------------------------------------------------------------------- /app/.cargo/config: -------------------------------------------------------------------------------- 1 | [target.thumbv7em-none-eabihf] 2 | rustflags = [ 3 | "-C", "link-arg=-Tdevice.ld", 4 | "-C", "link-arg=-Tlink.ld", 5 | "-C", "link-arg=-Tlog.ld", 6 | ] 7 | runner = "../qemu-gnuarmeclipse.sh" 8 | 9 | [target.thumbv7m-none-eabi] 10 | rustflags = [ 11 | "-C", "link-arg=-Tlink.ld", 12 | "-C", "link-arg=-Tlog.ld", 13 | ] 14 | runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" 15 | 16 | [build] 17 | target = "thumbv7em-none-eabihf" 18 | -------------------------------------------------------------------------------- /app/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote :3333 2 | monitor arm semihosting enable 3 | load 4 | monitor reset halt 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /app/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aligned" 5 | version = "0.2.0" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "app" 10 | version = "0.1.0" 11 | dependencies = [ 12 | "arch 0.1.0", 13 | "cortex-m-semihosting 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 14 | "device 0.1.0", 15 | "embedded-hal 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 16 | "kernel 0.1.0", 17 | "log 0.1.0", 18 | "rt 0.1.0", 19 | ] 20 | 21 | [[package]] 22 | name = "arch" 23 | version = "0.1.0" 24 | dependencies = [ 25 | "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "array-init" 30 | version = "0.0.4" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | dependencies = [ 33 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 34 | ] 35 | 36 | [[package]] 37 | name = "bare-metal" 38 | version = "0.2.4" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | dependencies = [ 41 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 42 | ] 43 | 44 | [[package]] 45 | name = "cortex-m" 46 | version = "0.5.8" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | dependencies = [ 49 | "aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 50 | "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 51 | "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 52 | ] 53 | 54 | [[package]] 55 | name = "cortex-m-semihosting" 56 | version = "0.3.2" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | dependencies = [ 59 | "cortex-m 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", 60 | ] 61 | 62 | [[package]] 63 | name = "device" 64 | version = "0.1.0" 65 | dependencies = [ 66 | "embedded-hal 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "rt 0.1.0", 69 | "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 71 | ] 72 | 73 | [[package]] 74 | name = "embedded-hal" 75 | version = "0.2.2" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | dependencies = [ 78 | "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 79 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 80 | ] 81 | 82 | [[package]] 83 | name = "kernel" 84 | version = "0.1.0" 85 | dependencies = [ 86 | "arch 0.1.0", 87 | "embedded-hal 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 88 | "rt 0.1.0", 89 | "util 0.1.0", 90 | ] 91 | 92 | [[package]] 93 | name = "log" 94 | version = "0.1.0" 95 | 96 | [[package]] 97 | name = "nb" 98 | version = "0.1.2" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | 101 | [[package]] 102 | name = "nodrop" 103 | version = "0.1.13" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | 106 | [[package]] 107 | name = "rt" 108 | version = "0.1.0" 109 | dependencies = [ 110 | "cortex-m-semihosting 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 111 | "log 0.1.0", 112 | ] 113 | 114 | [[package]] 115 | name = "rustc_version" 116 | version = "0.2.3" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | dependencies = [ 119 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 120 | ] 121 | 122 | [[package]] 123 | name = "semver" 124 | version = "0.9.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | dependencies = [ 127 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 128 | ] 129 | 130 | [[package]] 131 | name = "semver-parser" 132 | version = "0.7.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | 135 | [[package]] 136 | name = "util" 137 | version = "0.1.0" 138 | dependencies = [ 139 | "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 140 | ] 141 | 142 | [[package]] 143 | name = "vcell" 144 | version = "0.1.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | 147 | [[package]] 148 | name = "void" 149 | version = "1.0.2" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | 152 | [[package]] 153 | name = "volatile-register" 154 | version = "0.2.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | dependencies = [ 157 | "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 158 | ] 159 | 160 | [metadata] 161 | "checksum aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d39da9b88ae1a81c03c9c082b8db83f1d0e93914126041962af61034ab44c4a5" 162 | "checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" 163 | "checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a" 164 | "checksum cortex-m 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dab2164a0fc216781a47fc343347365112ae6917421d3fa4bac6faf0fbaaaec7" 165 | "checksum cortex-m-semihosting 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1dc2abec1a772e8bb697cad17d5710f180043caf8939820f0f6ba4b7ae2a4b5" 166 | "checksum embedded-hal 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9880e55238830314d41d88f1ac7a819d495799c3cc3bc392cc172bab26428c33" 167 | "checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc" 168 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 169 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 170 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 171 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 172 | "checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" 173 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 174 | "checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" 175 | -------------------------------------------------------------------------------- /app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "app" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | arch = { path = "../arch" } 9 | stm32f429zi = { path = "../devices/stm32f429zi" } 10 | rt = { path = "../rt" } 11 | log = { path = "../log" } 12 | kernel = { path = "../kernel" } 13 | user = { path = "../user" } 14 | util = { path = "../util" } 15 | cortex-m-semihosting = "0.3.5" 16 | embedded-hal = "0.2.5" 17 | 18 | [dependencies.smoltcp] 19 | version = "0.7.1" 20 | default-features = false 21 | features = ["ethernet", "proto-ipv4", "socket-tcp"] 22 | -------------------------------------------------------------------------------- /app/examples/arp.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arch::nvic::Nvic; 5 | use arch::systick::Systick; 6 | use stm32f429zi::eth::{Ethernet, EthernetTransmitter, RxEntry, TxEntry}; 7 | use stm32f429zi::exti::Exti; 8 | use stm32f429zi::gpio::Gpio; 9 | use stm32f429zi::irq::IrqId; 10 | use stm32f429zi::rcc::RCC; 11 | use stm32f429zi::serial::Serial; 12 | use stm32f429zi::syscfg::Syscfg; 13 | use embedded_hal::serial::{Read, Write}; 14 | use embedded_hal::fmt::*; 15 | use log::dhprintln; 16 | use rt::entry; 17 | use user::syscall::*; 18 | use util::avl_tree::Node; 19 | use util::linked_list::ListItem; 20 | use smoltcp::wire::{ 21 | ArpOperation, ArpPacket, ArpRepr, EthernetAddress, EthernetFrame, EthernetProtocol, 22 | EthernetRepr, Ipv4Address, 23 | }; 24 | use core::fmt::Write as CoreWrite; 25 | 26 | entry!(main); 27 | 28 | static mut TICK_PROCESS_ID: u32 = 0; 29 | 30 | pub fn main() -> ! { 31 | //let mut stdout = hstdout().unwrap(); 32 | //write!(stdout, "Hello, world!").unwrap(); 33 | 34 | //let process = process_create!(app_main, 1024); 35 | let registers = RCC.get_registers_ref(); 36 | let syscfg = Syscfg::new(0x4001_3800); 37 | 38 | unsafe { 39 | // enable USART3 40 | registers.apb1enr.write(1 << 18); 41 | // enable SYSCFG 42 | registers.apb2enr.write(1 << 14); 43 | // select RMII mode 44 | syscfg.pmc.modify(|val| val | (1 << 23)); 45 | // enable GPIOA - GPIOE, GPIOG-GPIOI, ETH and DMA1 46 | registers 47 | .ahb1enr 48 | .write(0b1_1101_1111 | (1 << 21) | (0b0111 << 25)); 49 | } 50 | 51 | let mut serial = Serial::usart3(); 52 | let systick = Systick::new(); 53 | let val = systick.get_ticks_per_10ms(); 54 | systick.clear_current(); 55 | systick.set_reload(val * 100); 56 | // systick.enable(); 57 | let gpioa = Gpio::new(0x4002_0000); 58 | let gpiob = Gpio::new(0x4002_0400); 59 | let gpioc = Gpio::new(0x4002_0800); 60 | let gpiod = Gpio::new(0x4002_0c00); 61 | let gpioe = Gpio::new(0x4002_1000); 62 | let gpiog = Gpio::new(0x4002_1800); 63 | let exti = Exti::new(0x4001_3C00); 64 | // For LED 65 | unsafe { 66 | gpiob.moder.modify(|val| (val | (0b1 << 28) | (0b1 << 14))); 67 | gpiob.bsrr.write(0x1 << 28); 68 | } 69 | // For button 70 | unsafe { 71 | gpioc.pupdr.modify(|val| (val | (0b10 << 26))); 72 | syscfg.exticr4.write(0b0010 << 4); 73 | exti.imr.write(0); 74 | exti.pr.write(0x1 << 13); 75 | exti.rtsr.modify(|val| (val | (0b1 << 13))); 76 | exti.imr.modify(|val| (val | (0b1 << 13))); 77 | } 78 | // For usart 79 | unsafe { 80 | gpiod.moder.write((0x2 << 16) | (0x2 << 18)); 81 | gpiod.afrh.write(0x7 | (0x7 << 4)); 82 | } 83 | // For nic 84 | unsafe { 85 | // pa1, pa2, pa7 86 | gpioa.moder.modify(|val| (val | 0b101000 | (0b10 << 14))); 87 | // AF11 88 | gpioa 89 | .afrl 90 | .modify(|val| (val | 0b0000_1011_1011_0000 | (0b1011 << 28))); 91 | gpioa.ospeedr.modify(|val| val | 0b111100 | (0b11 << 14)); 92 | // pb13 (RMII TXD1) 93 | gpiob.moder.modify(|val| val | (0b10 << 26)); 94 | // AF11 for pb13 95 | gpiob.afrh.modify(|val| (val | (0b1011 << 20))); 96 | gpiob.ospeedr.modify(|val| val | (0b11 << 26)); 97 | // pc1, 4, 5 98 | gpioc.moder.modify(|val| val | (0b10_10_00_00_10_00)); 99 | // AF11 for pc1, 4, 5 100 | gpioc 101 | .afrl 102 | .modify(|val| val | (0b1011_1011_0000_0000_1011 << 4)); 103 | gpioc.ospeedr.modify(|val| val | (0b11_11_00_00_11_00)); 104 | // pg11, pg13(RMII TX_EN, TXD0) 105 | gpiog 106 | .moder 107 | .modify(|val| val | (0b10 << 22) | (0b10_10 << 26)); 108 | gpiog 109 | .afrh 110 | .modify(|val| val | (0b1011 << 12) | (0b1011_1011 << 20)); 111 | gpiog 112 | .ospeedr 113 | .modify(|val| val | (0b11 << 22) | (0b11 << 26)); 114 | registers.ahb1rstr.modify(|val| val | (1 << 25)); 115 | registers.ahb1rstr.modify(|val| val & !(1 << 25)); 116 | } 117 | let nvic = Nvic::new(); 118 | // serial.send_buffer("hello dma world\r\n".as_bytes()); 119 | let eth = Ethernet::new(0x4002_8000); 120 | eth.init(); 121 | let mut ETH_TRANS_BUFF: [TxEntry; 2] = Default::default(); 122 | let mut ETH_RECV_BUFF: [RxEntry; 4] = Default::default(); 123 | let mut transmitter = EthernetTransmitter::new(ð, unsafe { &mut ETH_TRANS_BUFF }, unsafe { 124 | &mut ETH_RECV_BUFF 125 | }); 126 | transmitter.init(); 127 | for c in "hello world\n".chars() { 128 | serial.write(c).unwrap(); 129 | } 130 | 131 | loop { 132 | let status =eth.basic_status(); 133 | if status.is_link_detected() { 134 | const SIZE: usize = 14 + 28; // ETH + ARP 135 | let src_mac = EthernetAddress::from_bytes(&[0x00, 0x00, 0xde, 0xad, 0xbe, 0xef]); 136 | let arp_buffer = [0; 28]; 137 | 138 | let mut packet = 139 | ArpPacket::new_checked(arp_buffer).expect("ArpPacket: buffer size is not correct"); 140 | let arp = ArpRepr::EthernetIpv4 { 141 | operation: ArpOperation::Request, 142 | source_hardware_addr: src_mac, 143 | source_protocol_addr: Ipv4Address::new(192, 168, 1, 100), 144 | target_hardware_addr: EthernetAddress::from_bytes(&[0x00; 6]), 145 | target_protocol_addr: Ipv4Address::new(192, 168, 1, 254), 146 | }; 147 | arp.emit(&mut packet); 148 | 149 | let eth_buffer = [0; SIZE]; // ETH + ARP 150 | let mut frame = EthernetFrame::new_checked(eth_buffer) 151 | .expect("EthernetFrame: buffer size is not correct"); 152 | let header = EthernetRepr { 153 | src_addr: src_mac, 154 | dst_addr: EthernetAddress::BROADCAST, 155 | ethertype: EthernetProtocol::Arp, 156 | }; 157 | header.emit(&mut frame); 158 | frame.payload_mut().copy_from_slice(&packet.into_inner()); 159 | 160 | let result = transmitter.send(SIZE, |buf| { 161 | buf[0..SIZE].copy_from_slice(&frame.into_inner()); 162 | }); 163 | 164 | match result { 165 | Ok(_) => writeln!(serial, "ARP sent").unwrap(), 166 | Err(_) => writeln!(serial, "ARP failed").unwrap(), 167 | } 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/examples/ether.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arch::nvic::Nvic; 5 | use arch::systick::Systick; 6 | use stm32f429zi::eth::{Ethernet, EthernetTransmitter, RxEntry, TxEntry}; 7 | use stm32f429zi::exti::Exti; 8 | use stm32f429zi::gpio::Gpio; 9 | use stm32f429zi::irq::IrqId; 10 | use stm32f429zi::rcc::RCC; 11 | use stm32f429zi::serial::Serial; 12 | use stm32f429zi::syscfg::Syscfg; 13 | use embedded_hal::serial::{Read, Write}; 14 | use log::dhprintln; 15 | use rt::entry; 16 | use user::syscall::*; 17 | use util::avl_tree::Node; 18 | use util::linked_list::ListItem; 19 | 20 | entry!(main); 21 | 22 | static mut TICK_PROCESS_ID: u32 = 0; 23 | 24 | pub fn main() -> ! { 25 | //let mut stdout = hstdout().unwrap(); 26 | //write!(stdout, "Hello, world!").unwrap(); 27 | 28 | //let process = process_create!(app_main, 1024); 29 | let registers = RCC.get_registers_ref(); 30 | let syscfg = Syscfg::new(0x4001_3800); 31 | 32 | unsafe { 33 | // enable USART3 34 | registers.apb1enr.write(1 << 18); 35 | // enable SYSCFG 36 | registers.apb2enr.write(1 << 14); 37 | // select RMII mode 38 | syscfg.pmc.modify(|val| val | (1 << 23)); 39 | // enable GPIOA - GPIOE, GPIOG-GPIOI, ETH and DMA1 40 | registers 41 | .ahb1enr 42 | .write(0b1_1101_1111 | (1 << 21) | (0b0111 << 25)); 43 | } 44 | 45 | let mut serial = Serial::usart3(); 46 | let systick = Systick::new(); 47 | let val = systick.get_ticks_per_10ms(); 48 | systick.clear_current(); 49 | systick.set_reload(val * 100); 50 | // systick.enable(); 51 | let gpioa = Gpio::new(0x4002_0000); 52 | let gpiob = Gpio::new(0x4002_0400); 53 | let gpioc = Gpio::new(0x4002_0800); 54 | let gpiod = Gpio::new(0x4002_0c00); 55 | let gpioe = Gpio::new(0x4002_1000); 56 | let gpiog = Gpio::new(0x4002_1800); 57 | let exti = Exti::new(0x4001_3C00); 58 | // For LED 59 | unsafe { 60 | gpiob.moder.modify(|val| (val | (0b1 << 28) | (0b1 << 14))); 61 | gpiob.bsrr.write(0x1 << 28); 62 | } 63 | // For button 64 | unsafe { 65 | gpioc.pupdr.modify(|val| (val | (0b10 << 26))); 66 | syscfg.exticr4.write(0b0010 << 4); 67 | exti.imr.write(0); 68 | exti.pr.write(0x1 << 13); 69 | exti.rtsr.modify(|val| (val | (0b1 << 13))); 70 | exti.imr.modify(|val| (val | (0b1 << 13))); 71 | } 72 | // For usart 73 | unsafe { 74 | gpiod.moder.write((0x2 << 16) | (0x2 << 18)); 75 | gpiod.afrh.write(0x7 | (0x7 << 4)); 76 | } 77 | // For nic 78 | unsafe { 79 | // pa1, pa2, pa7 80 | gpioa.moder.modify(|val| (val | 0b101000 | (0b10 << 14))); 81 | // AF11 82 | gpioa 83 | .afrl 84 | .modify(|val| (val | 0b0000_1011_1011_0000 | (0b1011 << 28))); 85 | gpioa.ospeedr.modify(|val| val | 0b111100 | (0b11 << 14)); 86 | // pb13 (RMII TXD1) 87 | gpiob.moder.modify(|val| val | (0b10 << 26)); 88 | // AF11 for pb13 89 | gpiob.afrh.modify(|val| (val | (0b1011 << 20))); 90 | gpiob.ospeedr.modify(|val| val | (0b11 << 26)); 91 | // pc1, 4, 5 92 | gpioc.moder.modify(|val| val | (0b10_10_00_00_10_00)); 93 | // AF11 for pc1, 4, 5 94 | gpioc 95 | .afrl 96 | .modify(|val| val | (0b1011_1011_0000_0000_1011 << 4)); 97 | gpioc.ospeedr.modify(|val| val | (0b11_11_00_00_11_00)); 98 | // pg11, pg13(RMII TX_EN, TXD0) 99 | gpiog 100 | .moder 101 | .modify(|val| val | (0b10 << 22) | (0b10_10 << 26)); 102 | gpiog 103 | .afrh 104 | .modify(|val| val | (0b1011 << 12) | (0b1011_1011 << 20)); 105 | gpiog 106 | .ospeedr 107 | .modify(|val| val | (0b11 << 22) | (0b11 << 26)); 108 | registers.ahb1rstr.modify(|val| val | (1 << 25)); 109 | registers.ahb1rstr.modify(|val| val & !(1 << 25)); 110 | } 111 | let nvic = Nvic::new(); 112 | // serial.send_buffer("hello dma world\r\n".as_bytes()); 113 | let eth = Ethernet::new(0x4002_8000); 114 | eth.init(); 115 | let mut ETH_TRANS_BUFF: [TxEntry; 2] = Default::default(); 116 | let mut ETH_RECV_BUFF: [RxEntry; 4] = Default::default(); 117 | let mut transmitter = EthernetTransmitter::new(ð, unsafe { &mut ETH_TRANS_BUFF }, unsafe { 118 | &mut ETH_RECV_BUFF 119 | }); 120 | transmitter.init(); 121 | for c in "hello world\n".chars() { 122 | serial.write(c).unwrap(); 123 | } 124 | let message = "say hello\n\r"; 125 | for _i in 0..10 { 126 | transmitter 127 | .send(message.as_bytes().len(), |buff| { 128 | buff.copy_from_slice(message.as_bytes()); 129 | }) 130 | .unwrap_or_else(|_| { 131 | for c in "error\r\n".chars() { 132 | serial.write(c).unwrap(); 133 | } 134 | }); 135 | while transmitter.is_tx_running() {} 136 | } 137 | for _i in 0..10 { 138 | transmitter 139 | .send_buff(message.as_bytes()) 140 | .unwrap_or_else(|_| { 141 | for c in "error\r\n".chars() { 142 | serial.write(c).unwrap(); 143 | } 144 | }); 145 | while transmitter.is_tx_running() {} 146 | } 147 | loop { 148 | transmitter 149 | .poll() 150 | .and_then(|pkt| { 151 | for &p in pkt.iter() { 152 | serial.write(p as char).unwrap(); 153 | } 154 | Ok(()) 155 | }) 156 | .unwrap_or_else(|_| { 157 | for c in "error\r\n".chars() { 158 | serial.write(c).unwrap(); 159 | } 160 | }); 161 | } 162 | } 163 | 164 | 165 | pub fn serial_loopback() { 166 | // let mut serial = Serial::usart3(); 167 | // serial.read().map(|c| serial.write(c).unwrap()).unwrap(); 168 | } 169 | 170 | pub fn nothing() { 171 | let exti = Exti::new(0x4001_3C00); 172 | // let mut serial = Serial::usart3(); 173 | unsafe { 174 | exti.pr.write(0x1 << 13); 175 | /* 176 | for c in "pressed\n".chars() { 177 | serial.write(c).unwrap(); 178 | } 179 | */ 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /app/flash-example.sh: -------------------------------------------------------------------------------- 1 | IMAGE=$(pwd)/../target/thumbv7em-none-eabihf/release/examples/$1 2 | 3 | cargo build --release --example "$1" 4 | sudo openocd -f openocd.cfg -c "init; reset halt; flash write_image erase $IMAGE; verify_image $IMAGE; reset; shutdown" 5 | -------------------------------------------------------------------------------- /app/flash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | IMAGE=$(pwd)/../target/thumbv7em-none-eabihf/release/app 6 | 7 | cargo build --release 8 | sudo openocd -f openocd.cfg -c "init; reset halt; flash write_image erase $IMAGE; verify_image $IMAGE; reset; shutdown" 9 | -------------------------------------------------------------------------------- /app/openocd.cfg: -------------------------------------------------------------------------------- 1 | #interface 2 | interface hla 3 | hla_layout stlink 4 | hla_device_desc "ST-LINK/V2-1" 5 | hla_vid_pid 0x0483 0x374b 6 | 7 | set WORKAREASIZE 0x10000 8 | 9 | source [find target/stm32f4x.cfg] 10 | 11 | -------------------------------------------------------------------------------- /app/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(custom_test_frameworks)] 2 | #![test_runner(rt::test_runner)] 3 | #![reexport_test_harness_main = "test_main"] 4 | #![cfg_attr(test, no_main)] 5 | #![no_std] 6 | #![no_main] 7 | #![feature(asm)] 8 | 9 | use arch::nvic::Nvic; 10 | use arch::systick::Systick; 11 | use core::fmt::Write as CoreWrite; 12 | use core::mem::MaybeUninit; 13 | use cortex_m_semihosting::hio::hstdout; 14 | use stm32f429zi::eth::{Ethernet, EthernetTransmitter, RxEntry, TxEntry}; 15 | use stm32f429zi::exti::Exti; 16 | use stm32f429zi::gpio::Gpio; 17 | use stm32f429zi::irq::IrqId; 18 | use stm32f429zi::rcc::RCC; 19 | use stm32f429zi::serial::Serial; 20 | use stm32f429zi::syscfg::Syscfg; 21 | use embedded_hal::serial::{Read, Write}; 22 | use kernel::{interrupt_manager::InterruptManager, kernel::SysTick}; 23 | use kernel::kernel::Kernel; 24 | use kernel::message_manager::MessageManager; 25 | use kernel::process::Process; 26 | use kernel::process_list::ProcessListItem; 27 | use kernel::process_manager::{ProcessId, ProcessManager}; 28 | use kernel::scheduler::simple_scheduler::SimpleScheduler; 29 | use kernel::scheduler::Scheduler; 30 | use kernel::{process_create, process_register}; 31 | use log::dhprintln; 32 | use rt::entry; 33 | use user::syscall::*; 34 | use util::avl_tree::Node; 35 | use util::linked_list::ListItem; 36 | 37 | entry!(main); 38 | 39 | static mut TICK_PROCESS_ID: u32 = 0; 40 | 41 | pub fn main() -> ! { 42 | //let mut stdout = hstdout().unwrap(); 43 | //write!(stdout, "Hello, world!").unwrap(); 44 | 45 | let process = process_create!(app_main, 1024); 46 | let tick_process = process_create!(tick, 1024); 47 | let button_process = process_create!(button_callback, 1024); 48 | let serial_process = process_create!(serial_func, 1024); 49 | let registers = RCC.get_registers_ref(); 50 | let syscfg = Syscfg::new(0x4001_3800); 51 | 52 | unsafe { 53 | // enable USART3 54 | registers.apb1enr.write(1 << 18); 55 | // enable SYSCFG 56 | registers.apb2enr.write(1 << 14); 57 | // select RMII mode 58 | syscfg.pmc.modify(|val| val | (1 << 23)); 59 | // enable GPIOA - GPIOE, GPIOG-GPIOI, ETH and DMA1 60 | registers 61 | .ahb1enr 62 | .write(0b1_1101_1111 | (1 << 21) | (0b0111 << 25)); 63 | } 64 | 65 | let mut serial = Serial::usart3(); 66 | let systick = Systick::new(); 67 | let val = systick.get_ticks_per_10ms(); 68 | systick.clear_current(); 69 | systick.set_reload(val * 100); 70 | systick.enable(); 71 | let gpioa = Gpio::new(0x4002_0000); 72 | let gpiob = Gpio::new(0x4002_0400); 73 | let gpioc = Gpio::new(0x4002_0800); 74 | let gpiod = Gpio::new(0x4002_0c00); 75 | let gpioe = Gpio::new(0x4002_1000); 76 | let gpiog = Gpio::new(0x4002_1800); 77 | let exti = Exti::new(0x4001_3C00); 78 | // For LED 79 | unsafe { 80 | gpiob.moder.modify(|val| (val | (0b1 << 28) | (0b1 << 14))); 81 | gpiob.bsrr.write(0x1 << 28); 82 | } 83 | // For button 84 | unsafe { 85 | gpioc.pupdr.modify(|val| (val | (0b10 << 26))); 86 | syscfg.exticr4.write(0b0010 << 4); 87 | exti.imr.write(0); 88 | exti.pr.write(0x1 << 13); 89 | exti.rtsr.modify(|val| (val | (0b1 << 13))); 90 | exti.imr.modify(|val| (val | (0b1 << 13))); 91 | } 92 | // For usart 93 | unsafe { 94 | gpiod.moder.write((0x2 << 16) | (0x2 << 18)); 95 | gpiod.afrh.write(0x7 | (0x7 << 4)); 96 | } 97 | let nvic = Nvic::new(); 98 | for c in "hello world\n".chars() { 99 | serial.write(c).unwrap(); 100 | } 101 | let mut scheduler = SimpleScheduler::new(); 102 | let mut process_manager = ProcessManager::new(); 103 | process_register!(scheduler, process_manager, process); 104 | process_register!(scheduler, process_manager, tick_process, tick_process_id); 105 | process_register!(scheduler, process_manager, serial_process); 106 | process_register!(scheduler, process_manager, button_process); 107 | unsafe { 108 | TICK_PROCESS_ID = tick_process_id; 109 | } 110 | 111 | let mut interrupt_manager = InterruptManager::create(nvic); 112 | interrupt_manager.register(IrqId::USART3, serial_loopback); 113 | interrupt_manager.register(IrqId::EXTI15_10, nothing); 114 | 115 | let mut message_buff: [ListItem; 32] = 116 | unsafe { core::mem::MaybeUninit::uninit().assume_init() }; 117 | let message_manager = MessageManager::new(&mut message_buff); 118 | 119 | let mut kernel = Kernel::create( 120 | scheduler, 121 | serial, 122 | interrupt_manager, 123 | process_manager, 124 | message_manager, 125 | ); 126 | unsafe { 127 | let sp: u32; 128 | asm!("mov {0}, sp", out(reg) sp); 129 | dhprintln!("sp: {:x}", sp); 130 | } 131 | kernel.run(); 132 | } 133 | 134 | pub unsafe extern "C" fn app_main(_r0: usize, _r1: usize, _r2: usize) -> ! { 135 | let message: &str = "app_main"; 136 | print_str(message); 137 | loop { 138 | asm!( 139 | "mov r0, #5", 140 | "svc 1", 141 | out("r0") _, 142 | ); 143 | } 144 | } 145 | 146 | pub unsafe extern "C" fn button_callback() -> ! { 147 | let message: &str = "pressed\n"; 148 | let message_ptr = message.as_ptr(); 149 | let length = message.bytes().len(); 150 | loop { 151 | wait_for_interrupt(IrqId::EXTI15_10); 152 | print_str(message); 153 | } 154 | } 155 | 156 | pub unsafe extern "C" fn tick(_r0: usize, _r1: usize, _r2: usize) -> ! { 157 | let gpiob = Gpio::new(0x4002_0400); 158 | let mut status = false; 159 | let mut mode = 0; 160 | loop { 161 | match receive_message() { 162 | Some(command) => { 163 | mode = command; 164 | } 165 | None => {} 166 | } 167 | if mode == 0 { 168 | wait_for_event(); 169 | continue; 170 | } 171 | if status { 172 | gpiob.get_registers_ref().bsrr.write(0x1 << 23); 173 | } else { 174 | gpiob.get_registers_ref().bsrr.write(0x1 << 7); 175 | } 176 | status = !status; 177 | wait_for_systick(); 178 | } 179 | } 180 | 181 | pub unsafe extern "C" fn serial_func() -> ! { 182 | let mut serial = Serial::usart3(); 183 | let mut buff = ['\0' as u8; 64]; 184 | let mut pos = 0; 185 | loop { 186 | wait_for_interrupt(IrqId::USART3); 187 | serial.read().map(|c| { 188 | if c == '\n' { 189 | let command = &buff[0..pos]; 190 | if command == "blink".as_bytes() { 191 | send_message(TICK_PROCESS_ID, 1); 192 | } else if command == "stop".as_bytes() { 193 | send_message(TICK_PROCESS_ID, 0); 194 | } 195 | pos = 0; 196 | serial.write(c).unwrap(); 197 | } else { 198 | if pos < buff.len() { 199 | buff[pos] = c as u8; 200 | pos += 1; 201 | serial.write(c).unwrap(); 202 | } 203 | } 204 | }); 205 | } 206 | } 207 | 208 | pub fn serial_loopback() { 209 | // let mut serial = Serial::usart3(); 210 | // serial.read().map(|c| serial.write(c).unwrap()).unwrap(); 211 | } 212 | 213 | pub fn nothing() { 214 | let exti = Exti::new(0x4001_3C00); 215 | // let mut serial = Serial::usart3(); 216 | unsafe { 217 | exti.pr.write(0x1 << 13); 218 | /* 219 | for c in "pressed\n".chars() { 220 | serial.write(c).unwrap(); 221 | } 222 | */ 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /arch/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arch" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | volatile-register = "0.2" 9 | -------------------------------------------------------------------------------- /arch/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub mod nvic; 4 | pub mod systick; 5 | 6 | #[repr(C)] 7 | pub struct StackFrame { 8 | pub r0: u32, 9 | pub r1: u32, 10 | pub r2: u32, 11 | pub r3: u32, 12 | pub r12: u32, 13 | pub lr: u32, 14 | pub return_addr: u32, 15 | pub xpsr: u32, 16 | } 17 | 18 | impl StackFrame { 19 | pub unsafe fn from_ptr_mut<'a>(sp: *const u32) -> &'a mut StackFrame { 20 | &mut *(sp as *mut StackFrame) 21 | } 22 | pub unsafe fn from_ptr<'a>(sp: *const u32) -> &'a StackFrame { 23 | &*(sp as *const StackFrame) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /arch/src/nvic.rs: -------------------------------------------------------------------------------- 1 | use volatile_register::{RO, RW}; 2 | 3 | #[repr(C)] 4 | pub struct NvicRegisters { 5 | pub iser: [RW; 16], 6 | _reserved1: [u32; 16], 7 | pub icer: [RW; 16], 8 | _reserved2: [u32; 16], 9 | pub ispr: [RW; 16], 10 | _reserved3: [u32; 16], 11 | pub icpr: [RW; 16], 12 | _reserved4: [u32; 16], 13 | pub iabr: [RO; 16], 14 | _reserved5: [u32; 48], 15 | pub ipr: [RW; 4 * 124], 16 | } 17 | 18 | pub struct Nvic; 19 | 20 | impl Nvic { 21 | pub const fn new() -> Nvic { 22 | Nvic {} 23 | } 24 | 25 | pub fn get_registers_ref(&self) -> &NvicRegisters { 26 | let registers = 0xE000_E100 as *mut NvicRegisters; 27 | unsafe { &*registers } 28 | } 29 | 30 | pub fn enable(&self, id: u32) { 31 | let registers = self.get_registers_ref(); 32 | 33 | let idx = (id / 32) as usize; 34 | unsafe { 35 | registers.iser[idx].write(1 << (id % 32)); 36 | } 37 | } 38 | 39 | pub fn disable(&self, id: u32) { 40 | let registers = self.get_registers_ref(); 41 | 42 | let idx = (id / 32) as usize; 43 | unsafe { 44 | registers.icer[idx].write(1 << (id % 32)); 45 | } 46 | } 47 | 48 | pub fn is_pending(&self, id: u32) -> bool { 49 | let registers = self.get_registers_ref(); 50 | let idx = (id / 32) as usize; 51 | (registers.ispr[idx].read() & (1 << (id % 32))) > 0 52 | } 53 | 54 | pub fn clear_pending(&self, id: u32) { 55 | let registers = self.get_registers_ref(); 56 | let idx = (id / 32) as usize; 57 | unsafe { 58 | registers.icpr[idx].write(1 << (id % 32)); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /arch/src/systick.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | use volatile_register::{RO, RW}; 3 | 4 | #[repr(C)] 5 | pub struct SystickRegisters { 6 | pub csr: RW, 7 | pub rvr: RW, 8 | pub cvr: RW, 9 | pub calib: RO, 10 | } 11 | 12 | pub struct Systick {} 13 | 14 | impl Deref for Systick { 15 | type Target = SystickRegisters; 16 | 17 | fn deref(&self) -> &Self::Target { 18 | let registers = 0xE000_E010 as *mut SystickRegisters; 19 | unsafe { &*registers } 20 | } 21 | } 22 | 23 | impl Systick { 24 | pub const fn new() -> Systick { 25 | Systick {} 26 | } 27 | 28 | pub fn get_ticks_per_10ms(&self) -> u32 { 29 | self.calib.read() & 0x00FF_FFFF 30 | } 31 | 32 | pub fn clear_current(&self) { 33 | unsafe { 34 | self.cvr.write(0); 35 | } 36 | } 37 | 38 | pub fn set_reload(&self, val: u32) { 39 | unsafe { 40 | self.rvr.write(val); 41 | } 42 | } 43 | 44 | pub fn enable(&self) { 45 | unsafe { 46 | self.csr.modify(|val| (val | 0x3)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /devices/stm32f429zi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stm32f429zi" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | vcell = "0.1.0" 9 | embedded-hal = "0.2.2" 10 | nb = "0.1.2" 11 | rt = { path = "../../rt" } 12 | volatile-register = "0.2.0" 13 | aligned = "0.3.2" 14 | -------------------------------------------------------------------------------- /devices/stm32f429zi/build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, error::Error, fs::File, io::Write, path::PathBuf}; 2 | 3 | fn main() -> Result<(), Box> { 4 | // Put the linker script somewhere the linker can find it 5 | let out = PathBuf::from(env::var("OUT_DIR")?); 6 | 7 | File::create(out.join("device.ld"))?.write_all(include_bytes!("device.ld"))?; 8 | 9 | println!("cargo:rustc-link-search={}", out.display()); 10 | 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /devices/stm32f429zi/device.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH : ORIGIN = 0x08000000, LENGTH = 2M 4 | RAM : ORIGIN = 0x20000000, LENGTH = 112K 5 | } 6 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/dma.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | use core::ops::Deref; 3 | use volatile_register::{RO, RW, WO}; 4 | 5 | #[repr(C)] 6 | pub struct DmaRegisters { 7 | pub lisr: RO, 8 | pub hisr: RO, 9 | pub lifcr: WO, 10 | pub hifcr: WO, 11 | 12 | pub s0cr: RW, 13 | pub s0ndtr: RW, 14 | pub s0par: RW, 15 | pub s0m0ar: RW, 16 | pub s0m1ar: RW, 17 | pub s0fcr: RW, 18 | 19 | pub s1cr: RW, 20 | pub s1ndtr: RW, 21 | pub s1par: RW, 22 | pub s1m0ar: RW, 23 | pub s1m1ar: RW, 24 | pub s1fcr: RW, 25 | 26 | pub s2cr: RW, 27 | pub s2ndtr: RW, 28 | pub s2par: RW, 29 | pub s2m0ar: RW, 30 | pub s2m1ar: RW, 31 | pub s2fcr: RW, 32 | 33 | pub s3cr: RW, 34 | pub s3ndtr: RW, 35 | pub s3par: RW, 36 | pub s3m0ar: RW, 37 | pub s3m1ar: RW, 38 | pub s3fcr: RW, 39 | 40 | pub s4cr: RW, 41 | pub s4ndtr: RW, 42 | pub s4par: RW, 43 | pub s4m0ar: RW, 44 | pub s4m1ar: RW, 45 | pub s4fcr: RW, 46 | 47 | pub s5cr: RW, 48 | pub s5ndtr: RW, 49 | pub s5par: RW, 50 | pub s5m0ar: RW, 51 | pub s5m1ar: RW, 52 | pub s5fcr: RW, 53 | 54 | pub s6cr: RW, 55 | pub s6ndtr: RW, 56 | pub s6par: RW, 57 | pub s6m0ar: RW, 58 | pub s6m1ar: RW, 59 | pub s6fcr: RW, 60 | 61 | pub s7cr: RW, 62 | pub s7ndtr: RW, 63 | pub s7par: RW, 64 | pub s7m0ar: RW, 65 | pub s7m1ar: RW, 66 | pub s7fcr: RW, 67 | } 68 | 69 | pub struct Dma { 70 | base: u32, 71 | } 72 | 73 | impl Deref for Dma { 74 | type Target = DmaRegisters; 75 | 76 | fn deref(&self) -> &Self::Target { 77 | let registers = self.base as *mut DmaRegisters; 78 | unsafe { &*registers } 79 | } 80 | } 81 | 82 | impl Dma { 83 | pub const fn new(base: u32) -> Dma { 84 | Dma { base } 85 | } 86 | } 87 | 88 | pub trait Client { 89 | fn transfer(&self, buffer: &'static [u8], dest: u32, channel: u8); 90 | } 91 | 92 | pub enum Stream3 {} 93 | 94 | pub struct DmaClient { 95 | dma: Dma, 96 | _data: PhantomData, 97 | } 98 | 99 | impl DmaClient { 100 | pub fn dma1_stream3() -> DmaClient { 101 | DmaClient { 102 | dma: Dma::new(0x40026000), 103 | _data: PhantomData, 104 | } 105 | } 106 | } 107 | 108 | impl Client for DmaClient { 109 | fn transfer(&self, buffer: &'static [u8], dest: u32, channel: u8) { 110 | // disable stream 111 | unsafe { 112 | self.dma.s3cr.modify(|v| v & !1); 113 | } 114 | // wait for previous steam completion 115 | while self.dma.s3cr.read() & 1 > 0 {} 116 | unsafe { 117 | // clear interrupt 118 | self.dma.lifcr.write(0b11 << 26); 119 | // set peripheral port address 120 | self.dma.s3par.write(dest); 121 | // set memory address 122 | self.dma.s3m0ar.write(&buffer[0] as *const u8 as u32); 123 | // set the number of items 124 | self.dma.s3ndtr.write(buffer.len() as u32); 125 | // set the channel 126 | self.dma 127 | .s3cr 128 | .modify(|r| r & !(0b11 << 25) | ((channel as u32) << 25)); 129 | // set direction 130 | self.dma.s3cr.modify(|r| r & !(0b11 << 6) | (0b01 << 6)); // memory to peripheral 131 | // set increment mode 132 | self.dma.s3cr.modify(|r| r | (1 << 10)); // memory increment 133 | self.dma.s3cr.modify(|r| r & !(1 << 9)); // peripheral not increment 134 | // set data length 135 | self.dma.s3cr.modify(|r| r & !(0b11 << 11)); // psize is byte 136 | self.dma.s3cr.modify(|r| r & !(0b11 << 13)); // msize is byte 137 | // set transmit complete interrupt enable 138 | // self.dma.s3cr.modify(|r| r | (1 << 4)); 139 | 140 | // enable dma 141 | self.dma.s3cr.modify(|r| r | 1); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/eth.rs: -------------------------------------------------------------------------------- 1 | use aligned::{Aligned, A8}; 2 | use core::ops::{Deref, DerefMut}; 3 | use volatile_register::{RO, RW, WO}; 4 | 5 | #[repr(C)] 6 | pub struct EthernetMacRegister { 7 | cr: RW, 8 | ffr: RW, 9 | hthr: RW, 10 | htlr: RW, 11 | 12 | miiar: RW, 13 | miidr: RW, 14 | fcr: RW, 15 | vlancr: RW, 16 | vlantr: RW, 17 | 18 | _reserved0: u64, 19 | rwuffr: RW, 20 | pmtcsr: RW, 21 | 22 | _reserved1: u32, 23 | dbgr: RW, 24 | sr: RW, 25 | imr: RW, 26 | 27 | a0hr: RW, 28 | a0lr: RW, 29 | a1hr: RW, 30 | a1lr: RW, 31 | 32 | a2hr: RW, 33 | a2lr: RW, 34 | a3hr: RW, 35 | a3lr: RW, 36 | } 37 | 38 | #[repr(C)] 39 | pub struct EthernetMmcRegister { 40 | cr: RW, 41 | rir: RW, 42 | tir: RW, 43 | rimr: RW, 44 | 45 | timr: RW, 46 | _reserved3: [u32; 3], 47 | 48 | _reserved4: [u32; 8], 49 | 50 | // 0x40 51 | _reserved5: [u32; 3], 52 | tgfsccr: RW, 53 | 54 | // 0x50 55 | tgfmsccr: RW, 56 | _reserved6: [u32; 3], 57 | 58 | // 0x60 59 | _reserved7: [u32; 2], 60 | tgfcr: RW, 61 | _reserved8: u32, 62 | 63 | _reserved9: [u32; 8], 64 | 65 | // 0x90 66 | _reserved10: u32, 67 | rfcecr: RW, 68 | rfaecr: RW, 69 | _reserved11: u32, 70 | 71 | _reserved12: [u32; 8], 72 | 73 | // 0xC0 74 | _reserved13: u32, 75 | rgufcr: RW, 76 | } 77 | 78 | #[repr(C)] 79 | pub struct EthernetPtpRegister { 80 | tscr: RW, 81 | ssir: RW, 82 | tshr: RW, 83 | tslr: RW, 84 | 85 | tshur: RW, 86 | tslur: RW, 87 | tsar: RW, 88 | tthr: RW, 89 | 90 | ttlr: RW, 91 | _reseverd17: u32, 92 | tssr: RW, 93 | ppscr: RW, 94 | } 95 | 96 | #[repr(C)] 97 | pub struct EthernetDmaRegister { 98 | bmr: RW, 99 | tpdr: RW, 100 | rpdr: RW, 101 | rdlar: RW, 102 | 103 | tdlar: RW, 104 | sr: RW, 105 | omr: RW, 106 | ier: RW, 107 | 108 | mfbocr: RW, 109 | rswtr: RW, 110 | _reserved0: [u32; 2], 111 | 112 | _reserved1: [u32; 4], 113 | 114 | _reserved2: [u32; 2], 115 | chtdr: RW, 116 | chrdr: RW, 117 | 118 | chtrar: RW, 119 | chrbar: RW, 120 | } 121 | 122 | pub struct EthernetMac { 123 | base: u32, 124 | } 125 | 126 | pub struct EthernetMmc { 127 | base: u32, 128 | } 129 | 130 | pub struct EthernetPtp { 131 | base: u32, 132 | } 133 | 134 | pub struct EthernetDma { 135 | base: u32, 136 | } 137 | 138 | pub struct Ethernet { 139 | mac: EthernetMac, 140 | mmc: EthernetMmc, 141 | ptp: EthernetPtp, 142 | dma: EthernetDma, 143 | } 144 | 145 | impl Deref for EthernetMac { 146 | type Target = EthernetMacRegister; 147 | 148 | fn deref(&self) -> &Self::Target { 149 | let registers = self.base as *mut EthernetMacRegister; 150 | unsafe { &*registers } 151 | } 152 | } 153 | 154 | impl Deref for EthernetMmc { 155 | type Target = EthernetMmcRegister; 156 | 157 | fn deref(&self) -> &Self::Target { 158 | let registers = self.base as *mut EthernetMmcRegister; 159 | unsafe { &*registers } 160 | } 161 | } 162 | 163 | impl Deref for EthernetPtp { 164 | type Target = EthernetPtpRegister; 165 | 166 | fn deref(&self) -> &Self::Target { 167 | let registers = self.base as *mut EthernetPtpRegister; 168 | unsafe { &*registers } 169 | } 170 | } 171 | 172 | impl Deref for EthernetDma { 173 | type Target = EthernetDmaRegister; 174 | 175 | fn deref(&self) -> &Self::Target { 176 | let registers = self.base as *mut EthernetDmaRegister; 177 | unsafe { &*registers } 178 | } 179 | } 180 | 181 | mod phy { 182 | pub const REG_BCR: u8 = 0; 183 | pub const REG_BSR: u8 = 1; 184 | pub const REG_ID1R: u8 = 2; 185 | pub const REG_ID2R: u8 = 3; 186 | pub const REG_ANAR: u8 = 4; 187 | pub const REG_ANLPAR: u8 = 5; 188 | pub const REG_ANER: u8 = 6; 189 | pub const REG_ANNPTR: u8 = 7; 190 | pub const REG_ANNPRR: u8 = 8; 191 | 192 | pub const REG_MMD_ACR: u8 = 13; 193 | pub const REG_MMD_ADR: u8 = 14; 194 | 195 | pub const REG_EDPD_CTR: u8 = 16; 196 | 197 | pub const REG_MSR: u8 = 17; 198 | pub const REG_SMR: u8 = 18; 199 | 200 | pub const REG_TDR_PDCR: u8 = 24; 201 | pub const REG_TDR_CSR: u8 = 25; 202 | 203 | pub const REG_SECR: u8 = 26; 204 | pub const REG_SCSIR: u8 = 27; 205 | pub const REG_CLR: u8 = 28; 206 | pub const REG_ISFR: u8 = 29; 207 | pub const REG_IMR: u8 = 30; 208 | pub const REG_SCSR: u8 = 31; 209 | } 210 | 211 | pub struct BasicStatus { 212 | value: u16, 213 | } 214 | 215 | impl BasicStatus { 216 | pub fn is_link_detected(&self) -> bool { 217 | self.value & (1 << 2) > 0 218 | } 219 | } 220 | 221 | impl Ethernet { 222 | pub const fn new(base: u32) -> Ethernet { 223 | Ethernet { 224 | mac: EthernetMac { base }, 225 | mmc: EthernetMmc { base: base + 0x100 }, 226 | ptp: EthernetPtp { base: base + 0x700 }, 227 | dma: EthernetDma { 228 | base: base + 0x1000, 229 | }, 230 | } 231 | } 232 | 233 | fn read_phy_reg(&self, reg: u8) -> u32 { 234 | unsafe { 235 | self.mac 236 | .miiar 237 | .modify(|val| (val & !(0x1f << 6) | ((reg as u32) << 6)) & !(1 << 1) | 1); 238 | while self.mac.miiar.read() & 1 > 0 {} 239 | // wait until MB is cleared 240 | self.mac.miidr.read() 241 | } 242 | } 243 | 244 | fn write_phy_reg(&self, reg: u8, data: u32) { 245 | unsafe { 246 | self.mac.miidr.write(data); 247 | self.mac 248 | .miiar 249 | .modify(|val| val & !(0x1f << 6) | ((reg as u32) << 6) | (1 << 1) | 1); 250 | // wait until MB is cleared 251 | while self.mac.miiar.read() & 1 > 0 {} 252 | } 253 | } 254 | 255 | fn modify_phy_reg(&self, reg: u8, f: F) 256 | where 257 | F: FnOnce(u32) -> u32, 258 | { 259 | unsafe { 260 | self.mac 261 | .miiar 262 | .modify(|val| (val & !(0x1f << 6) | ((reg as u32) << 6)) & !(1 << 1) | 1); 263 | while self.mac.miiar.read() & 1 > 0 {} 264 | // wait until MB is cleared 265 | let val = self.mac.miidr.read(); 266 | self.mac.miidr.write(f(val)); 267 | self.mac 268 | .miiar 269 | .modify(|val| val & !(0x1f << 6) | ((reg as u32) << 6) | (1 << 1) | 1); 270 | while self.mac.miiar.read() & 1 > 0 {} 271 | } 272 | } 273 | 274 | pub fn init(&self) { 275 | unsafe { 276 | // reset dma 277 | self.dma.bmr.modify(|val| val | 1); 278 | while self.dma.bmr.read() & 1 > 0 {} 279 | 280 | // hclk div 16 281 | self.mac 282 | .miiar 283 | .modify(|val| (val & !(0b11 << 2)) | 0b010 << 2); 284 | 285 | // reset phy 286 | // set soft reset 287 | self.write_phy_reg(phy::REG_BCR, 1 << 15); 288 | // set auto negotiation 289 | self.modify_phy_reg(phy::REG_BCR, |val| val | (1 << 12) | (1 << 9)); 290 | 291 | // configure mac 292 | // CSTF, FES, DM, APCS, RE, TE 293 | self.mac.cr.modify(|val| { 294 | val | (1 << 25) | (1 << 14) | (1 << 11) | (1 << 7) | (1 << 2) | (1 << 3) 295 | }); 296 | 297 | // RA, PM 298 | self.mac.ffr.modify(|val| val | (1 << 31) | 1); 299 | 300 | // set pause time 100 301 | self.mac 302 | .fcr 303 | .modify(|val| (val & !(0xffff << 16)) | (0x1000 << 16)); 304 | 305 | // DTCEFD, RSF, DFRF, TSF, FEF, OSF 306 | self.dma.omr.modify(|val| { 307 | val | (1 << 26) | (1 << 25) | (1 << 24) | (1 << 21) | (1 << 7) | (1 << 2) 308 | }); 309 | 310 | // AAB, FB, RDP = 32, PBL = 32, PM = 01, USP 311 | self.dma.bmr.modify(|val| { 312 | (val & !(0x3f << 8) & !(0b11 << 14) & !(0x3f << 17)) 313 | | (1 << 25) 314 | | (1 << 16) 315 | | (32 << 17) 316 | | (32 << 8) 317 | | (0b01 << 14) 318 | | (1 << 23) 319 | }); 320 | 321 | while self.read_phy_reg(phy::REG_SCSR) & (1 << 12) == 0 {} 322 | } 323 | } 324 | 325 | pub fn basic_status(&self) -> BasicStatus { 326 | let value = self.read_phy_reg(phy::REG_BSR) as u16; 327 | BasicStatus { 328 | value, 329 | } 330 | } 331 | } 332 | 333 | const VLAN_MAX_SIZE: usize = 1522; 334 | 335 | #[repr(C)] 336 | pub struct TxEntry { 337 | desc: Aligned, 338 | buff: Aligned, 339 | } 340 | 341 | impl TxEntry { 342 | fn get_packet(&mut self, length: usize) -> Option { 343 | if length > VLAN_MAX_SIZE { 344 | return None; 345 | } 346 | 347 | let ptr = &self.desc[0] as *const u32; 348 | if unsafe { core::ptr::read_volatile(ptr) } & (1 << 31) == 0 { 349 | self.desc[1] &= !0x1fff; 350 | self.desc[1] |= length as u32; 351 | self.desc[2] = self.buff.as_ptr() as u32; 352 | Some(TxPacket { 353 | entry: self, 354 | length, 355 | }) 356 | } else { 357 | None 358 | } 359 | } 360 | fn get_packet_with<'a>(&'a mut self, buff: &'a [u8]) -> Option { 361 | let length = buff.len(); 362 | if length > VLAN_MAX_SIZE { 363 | return None; 364 | } 365 | 366 | let ptr = &self.desc[0] as *const u32; 367 | if unsafe { core::ptr::read_volatile(ptr) } & (1 << 31) == 0 { 368 | self.desc[1] &= !0x1fff; 369 | self.desc[1] |= length as u32; 370 | self.desc[2] = buff.as_ptr() as u32; 371 | Some(TxPacket { 372 | entry: self, 373 | length, 374 | }) 375 | } else { 376 | None 377 | } 378 | } 379 | } 380 | 381 | impl Default for TxEntry { 382 | fn default() -> Self { 383 | TxEntry { 384 | desc: Aligned([0; 4]), 385 | buff: Aligned([0; VLAN_MAX_SIZE]), 386 | } 387 | } 388 | } 389 | 390 | pub struct TxPacket<'a> { 391 | entry: &'a mut TxEntry, 392 | length: usize, 393 | } 394 | 395 | impl<'a> TxPacket<'a> { 396 | fn start_send(&mut self) { 397 | let ptr = &mut self.entry.desc[0] as *mut u32; 398 | let value = unsafe { core::ptr::read_volatile(ptr) }; 399 | let value = value | (1 << 29) | (1 << 28); 400 | unsafe { core::ptr::write_volatile(ptr, value) }; 401 | // Set owned bit, CIC, LS, FS 402 | unsafe { core::ptr::write_volatile(ptr, value | (1 << 31)) }; 403 | } 404 | } 405 | 406 | impl<'a> Deref for TxPacket<'a> { 407 | type Target = [u8]; 408 | fn deref(&self) -> &Self::Target { 409 | &self.entry.buff[0..self.length] 410 | } 411 | } 412 | 413 | impl<'a> DerefMut for TxPacket<'a> { 414 | fn deref_mut(&mut self) -> &mut Self::Target { 415 | &mut self.entry.buff[0..self.length] 416 | } 417 | } 418 | 419 | #[repr(C)] 420 | pub struct RxEntry { 421 | desc: Aligned, 422 | buff: Aligned, 423 | } 424 | 425 | impl RxEntry { 426 | pub fn poll(&mut self) -> Result { 427 | let ptr = &self.desc[0] as *const u32; 428 | while unsafe { core::ptr::read_volatile(ptr) } & (1 << 31) > 0 {} 429 | // LS and FS are set 430 | if self.desc[0] & (1 << 8) > 0 && self.desc[0] & (1 << 9) > 0 { 431 | let frame_len = (self.desc[1] & 0xfff) as usize; 432 | Ok(RxPacket { 433 | entry: self, 434 | length: frame_len, 435 | }) 436 | } else { 437 | Err(RxError::NoBuffer) 438 | } 439 | } 440 | } 441 | 442 | impl Default for RxEntry { 443 | fn default() -> Self { 444 | RxEntry { 445 | desc: Aligned([0; 4]), 446 | buff: Aligned([0; VLAN_MAX_SIZE]), 447 | } 448 | } 449 | } 450 | 451 | pub struct RxPacket<'a> { 452 | entry: &'a mut RxEntry, 453 | length: usize, 454 | } 455 | 456 | impl<'a> RxPacket<'a> {} 457 | 458 | impl<'a> Deref for RxPacket<'a> { 459 | type Target = [u8]; 460 | fn deref(&self) -> &Self::Target { 461 | &self.entry.buff[0..self.length] 462 | } 463 | } 464 | 465 | impl<'a> DerefMut for RxPacket<'a> { 466 | fn deref_mut(&mut self) -> &mut Self::Target { 467 | &mut self.entry.buff[0..self.length] 468 | } 469 | } 470 | 471 | impl<'a> Drop for RxPacket<'a> { 472 | fn drop(&mut self) { 473 | // set own bit 474 | self.entry.desc[0] |= 1 << 31; 475 | } 476 | } 477 | 478 | pub struct EthernetTransmitter<'a> { 479 | eth: &'a Ethernet, 480 | tx_entries: &'a mut [TxEntry], 481 | rx_entries: &'a mut [RxEntry], 482 | tx_pos: usize, 483 | rx_pos: usize, 484 | } 485 | 486 | pub enum TxError { 487 | NoBuffer, 488 | } 489 | pub enum RxError { 490 | NoBuffer, 491 | } 492 | 493 | impl<'a> EthernetTransmitter<'a> { 494 | pub fn new( 495 | eth: &'a Ethernet, 496 | tx_entries: &'a mut [TxEntry], 497 | rx_entries: &'a mut [RxEntry], 498 | ) -> EthernetTransmitter<'a> { 499 | EthernetTransmitter { 500 | eth, 501 | tx_entries, 502 | rx_entries, 503 | tx_pos: 0, 504 | rx_pos: 0, 505 | } 506 | } 507 | 508 | pub fn init(&mut self) { 509 | for i in 0..self.tx_entries.len() { 510 | // TCH 511 | self.tx_entries[i].desc[0] = 1 << 20; 512 | self.tx_entries[i].desc[1] = 0; 513 | self.tx_entries[i].desc[2] = 0; 514 | if i + 1 != self.tx_entries.len() { 515 | self.tx_entries[i].desc[3] = &self.tx_entries[i + 1].desc[0] as *const u32 as u32; 516 | } else { 517 | self.tx_entries[i].desc[3] = 0; 518 | // TER 519 | self.tx_entries[i].desc[0] |= 1 << 21; 520 | } 521 | } 522 | for i in 0..self.rx_entries.len() { 523 | // OWN 524 | self.rx_entries[i].desc[0] = 1 << 31; 525 | // RCH and RBS (buffer size) 526 | self.rx_entries[i].desc[1] = 1 << 14 | VLAN_MAX_SIZE as u32; 527 | self.rx_entries[i].desc[2] = self.rx_entries[i].buff.as_ptr() as u32; 528 | if i + 1 != self.rx_entries.len() { 529 | self.rx_entries[i].desc[3] = &self.rx_entries[i + 1].desc[0] as *const u32 as u32; 530 | } else { 531 | self.rx_entries[i].desc[3] = 0; 532 | // RER 533 | self.rx_entries[i].desc[1] |= 1 << 15; 534 | } 535 | } 536 | let tx_addr = &self.tx_entries[0].desc[0] as *const u32 as u32; 537 | let rx_addr = &self.rx_entries[0].desc[0] as *const u32 as u32; 538 | unsafe { 539 | self.eth.dma.tdlar.write(tx_addr); 540 | self.eth.dma.rdlar.write(rx_addr); 541 | } 542 | self.tx_pos = 0; 543 | // enable ST, SR 544 | unsafe { 545 | self.eth.dma.omr.modify(|v| v | (1 << 13) | (1 << 1)); 546 | } 547 | } 548 | 549 | pub fn poll(&mut self) -> Result { 550 | let running_state = self.eth.dma.sr.read() & (0b111 << 17) >> 17; 551 | if running_state != 0b001 552 | && running_state != 0b011 553 | && running_state != 0b101 554 | && running_state != 0b111 555 | { 556 | unsafe { 557 | self.eth.dma.rpdr.write(1); 558 | } 559 | } 560 | 561 | let rx_len = self.rx_entries.len(); 562 | let result = self.rx_entries[self.rx_pos].poll(); 563 | self.rx_pos += 1; 564 | self.rx_pos %= rx_len; 565 | result 566 | } 567 | 568 | pub fn send_buff(&mut self, buff: &'a [u8]) -> Result<(), TxError> { 569 | match self.tx_entries[self.tx_pos].get_packet_with(buff) { 570 | Some(mut pkt) => { 571 | pkt.start_send(); 572 | unsafe { 573 | self.eth.dma.tpdr.write(1); 574 | } 575 | 576 | self.tx_pos += 1; 577 | self.tx_pos %= self.tx_entries.len(); 578 | Ok(()) 579 | } 580 | None => Err(TxError::NoBuffer), 581 | } 582 | } 583 | 584 | pub fn send R, R>( 585 | &mut self, 586 | length: usize, 587 | f: F, 588 | ) -> Result { 589 | match self.tx_entries[self.tx_pos].get_packet(length) { 590 | Some(mut pkt) => { 591 | let r = f(pkt.deref_mut()); 592 | pkt.start_send(); 593 | unsafe { 594 | self.eth.dma.tpdr.write(1); 595 | } 596 | 597 | self.tx_pos += 1; 598 | self.tx_pos %= self.tx_entries.len(); 599 | Ok(r) 600 | } 601 | None => Err(TxError::NoBuffer), 602 | } 603 | } 604 | 605 | pub fn is_tx_running(&self) -> bool { 606 | let running_state = (self.eth.dma.sr.read() & (0b111 << 20)) >> 20; 607 | match running_state { 608 | 0b001 | 0b010 | 0b011 | 0b111 => true, 609 | _ => false, 610 | } 611 | } 612 | } 613 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/exti.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | use volatile_register::RW; 3 | 4 | #[repr(C)] 5 | pub struct ExtiRegisters { 6 | pub imr: RW, 7 | pub emr: RW, 8 | pub rtsr: RW, 9 | pub ftsr: RW, 10 | pub swier: RW, 11 | pub pr: RW, 12 | } 13 | 14 | pub struct Exti { 15 | base: u32, 16 | } 17 | 18 | impl Deref for Exti { 19 | type Target = ExtiRegisters; 20 | 21 | fn deref(&self) -> &Self::Target { 22 | let registers = self.base as *mut ExtiRegisters; 23 | unsafe { &*registers } 24 | } 25 | } 26 | 27 | impl Exti { 28 | pub const fn new(base: u32) -> Exti { 29 | Exti { base } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/gpio.rs: -------------------------------------------------------------------------------- 1 | extern crate embedded_hal as hal; 2 | use core::ops::Deref; 3 | use volatile_register::{RO, RW}; 4 | 5 | #[repr(C)] 6 | pub struct GpioRegisters { 7 | pub moder: RW, 8 | pub otyper: RW, 9 | pub ospeedr: RW, 10 | pub pupdr: RW, 11 | pub idr: RO, 12 | pub odr: RW, 13 | pub bsrr: RW, 14 | pub lckr: RW, 15 | pub afrl: RW, 16 | pub afrh: RW, 17 | } 18 | 19 | pub struct Gpio { 20 | registers: *mut GpioRegisters, 21 | } 22 | 23 | impl Gpio { 24 | pub fn new(base: usize) -> Gpio { 25 | Gpio { 26 | registers: base as *mut GpioRegisters, 27 | } 28 | } 29 | 30 | pub fn get_registers_ref(&self) -> &GpioRegisters { 31 | unsafe { &*self.registers } 32 | } 33 | } 34 | 35 | impl Deref for Gpio { 36 | type Target = GpioRegisters; 37 | 38 | fn deref(&self) -> &Self::Target { 39 | let registers = self.registers as *mut GpioRegisters; 40 | unsafe { &*registers } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/irq.rs: -------------------------------------------------------------------------------- 1 | use rt::Vector; 2 | 3 | pub mod IrqId { 4 | pub const USART3: u32 = 39; 5 | pub const EXTI15_10: u32 = 40; 6 | } 7 | 8 | #[link_section = ".irq_table"] 9 | #[used] 10 | #[no_mangle] 11 | pub static mut IRQS: [Vector; 91] = [ 12 | Vector { reserved: 0 }, // WWDG (0) 13 | Vector { reserved: 0 }, // PVD (1) 14 | Vector { reserved: 0 }, // TAMP_STAMP (2) 15 | Vector { reserved: 0 }, // RTC_WKUP (3) 16 | Vector { reserved: 0 }, // FLASH (4) 17 | Vector { reserved: 0 }, // RCC (5) 18 | Vector { reserved: 0 }, // EXTI0 (6) 19 | Vector { reserved: 0 }, // EXTI1 (7) 20 | Vector { reserved: 0 }, // EXTI2 (8) 21 | Vector { reserved: 0 }, // EXTI3 (9) 22 | Vector { reserved: 0 }, // EXTI4 (10) 23 | Vector { reserved: 0 }, // DMA1_Stream0 (11) 24 | Vector { reserved: 0 }, // DMA1_Stream1 (12) 25 | Vector { reserved: 0 }, // DMA1_Stream2 (13) 26 | Vector { reserved: 0 }, // DMA1_Stream3 (14) 27 | Vector { reserved: 0 }, // DMA1_Stream4 (15) 28 | Vector { reserved: 0 }, // DMA1_Stream5 (16) 29 | Vector { reserved: 0 }, // DMA1_Stream6 (17) 30 | Vector { reserved: 0 }, // ADC (18) 31 | Vector { reserved: 0 }, // CAN1_TX (19) 32 | Vector { reserved: 0 }, // CAN1_RX0 (20) 33 | Vector { reserved: 0 }, // CAN1_RX1 (21) 34 | Vector { reserved: 0 }, // CAN1_SCE (22) 35 | Vector { reserved: 0 }, // EXTI9_5 (23) 36 | Vector { reserved: 0 }, // TIM1_BRK_TIM9 (24) 37 | Vector { reserved: 0 }, // TIM1_UP_TIM10 (25) 38 | Vector { reserved: 0 }, // TIM1_TRG_COM_TIM11 (26) 39 | Vector { reserved: 0 }, // TIM1_CC (27) 40 | Vector { reserved: 0 }, // TIM2 (28) 41 | Vector { reserved: 0 }, // TIM3 (29) 42 | Vector { reserved: 0 }, // TIM4 (30) 43 | Vector { reserved: 0 }, // I2C1_EV (31) 44 | Vector { reserved: 0 }, // I2C1_ER (32) 45 | Vector { reserved: 0 }, // I2C2_EV (33) 46 | Vector { reserved: 0 }, // I2C2_ER (34) 47 | Vector { reserved: 0 }, // SPI1 (35) 48 | Vector { reserved: 0 }, // SPI2 (36) 49 | Vector { reserved: 0 }, // USART1 (37) 50 | Vector { reserved: 0 }, // USART2 (38) 51 | Vector { reserved: 0 }, // USART3 (39) 52 | Vector { reserved: 0 }, // EXTI15_10 (40) 53 | Vector { reserved: 0 }, // RTC_Alarm (41) 54 | Vector { reserved: 0 }, // OTG_FS_WKUP (42) 55 | Vector { reserved: 0 }, // TIM8_BRK_TIM12 (43) 56 | Vector { reserved: 0 }, // TIM8_UP_TIM13 (44) 57 | Vector { reserved: 0 }, // TIM8_TRG_COM_TIM14 (45) 58 | Vector { reserved: 0 }, // TIM8_CC (46) 59 | Vector { reserved: 0 }, // DMA1_Stream7 (47) 60 | Vector { reserved: 0 }, // FMC (48) 61 | Vector { reserved: 0 }, // SDIO (49) 62 | Vector { reserved: 0 }, // TIM5 (50) 63 | Vector { reserved: 0 }, // SPI3 (51) 64 | Vector { reserved: 0 }, // UART4 (52) 65 | Vector { reserved: 0 }, // UART5 (53) 66 | Vector { reserved: 0 }, // TIM6_DAC (54) 67 | Vector { reserved: 0 }, // TIM7 (55) 68 | Vector { reserved: 0 }, // DMA2_Stream0 (56) 69 | Vector { reserved: 0 }, // DMA2_Stream1 (57) 70 | Vector { reserved: 0 }, // DMA2_Stream2 (58) 71 | Vector { reserved: 0 }, // DMA2_Stream3 (59) 72 | Vector { reserved: 0 }, // DMA2_Stream4 (60) 73 | Vector { reserved: 0 }, // ETH (61) 74 | Vector { reserved: 0 }, // ETH_WKUP (62) 75 | Vector { reserved: 0 }, // CAN2_TX (63) 76 | Vector { reserved: 0 }, // CAN2_RX0 (64) 77 | Vector { reserved: 0 }, // CAN2_RX1 (65) 78 | Vector { reserved: 0 }, // CAN2_SCE (66) 79 | Vector { reserved: 0 }, // OTG_FS (67) 80 | Vector { reserved: 0 }, // DMA2_Stream5 (68) 81 | Vector { reserved: 0 }, // DMA2_Stream6 (69) 82 | Vector { reserved: 0 }, // DMA2_Stream7 (70) 83 | Vector { reserved: 0 }, // USART6 (71) 84 | Vector { reserved: 0 }, // I2C3_EV (72) 85 | Vector { reserved: 0 }, // I2C3_ER (73) 86 | Vector { reserved: 0 }, // OTG_HS_EP1_OUT (74) 87 | Vector { reserved: 0 }, // OTG_HS_EP1_IN (75) 88 | Vector { reserved: 0 }, // OTG_HS_WKUP (76) 89 | Vector { reserved: 0 }, // OTG_HS (77) 90 | Vector { reserved: 0 }, // DCMI (78) 91 | Vector { reserved: 0 }, // CRYP (79) 92 | Vector { reserved: 0 }, // HASH_RNG (80) 93 | Vector { reserved: 0 }, // FPU (81) 94 | Vector { reserved: 0 }, // USART7 (82) 95 | Vector { reserved: 0 }, // USART8 (83) 96 | Vector { reserved: 0 }, // SPI4 (84) 97 | Vector { reserved: 0 }, // SPI5 (85) 98 | Vector { reserved: 0 }, // SPI6 (86) 99 | Vector { reserved: 0 }, // SAI1 (87) 100 | Vector { reserved: 0 }, // LCD-TFT (88) 101 | Vector { reserved: 0 }, // LCD-TFT (89) 102 | Vector { reserved: 0 }, // DMA2D(90) 103 | ]; 104 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "rlib"] 2 | #![no_std] 3 | #![feature(asm)] 4 | 5 | pub mod dma; 6 | pub mod eth; 7 | pub mod exti; 8 | pub mod gpio; 9 | pub mod irq; 10 | pub mod rcc; 11 | pub mod serial; 12 | pub mod syscfg; 13 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/rcc.rs: -------------------------------------------------------------------------------- 1 | use volatile_register::RW; 2 | 3 | #[repr(C)] 4 | pub struct RccRegisters { 5 | pub cr: RW, 6 | pub pllcfgr: RW, 7 | pub cfgr: RW, 8 | pub cir: RW, 9 | 10 | // 0x10 11 | pub ahb1rstr: RW, 12 | pub ahb2rstr: RW, 13 | pub ahb3rstr: RW, 14 | _reserved1: [u8; 4usize], 15 | 16 | // 0x20 17 | pub apb1rstr: RW, 18 | pub apb2rstr: RW, 19 | _reserved2: [u8; 8usize], 20 | 21 | // 0x30 22 | pub ahb1enr: RW, 23 | pub ahb2enr: RW, 24 | pub ahb3enr: RW, 25 | _reserved3: [u8; 4usize], 26 | 27 | // 0x40 28 | pub apb1enr: RW, 29 | pub apb2enr: RW, 30 | _reserved4: [u8; 8usize], 31 | 32 | // 0x50 33 | pub ahb1lpenr: RW, 34 | pub ahb2lpern: RW, 35 | pub ahb3lpenr: RW, 36 | _reserved5: [u8; 4usize], 37 | 38 | // 0x60 39 | pub apb1lpenr: RW, 40 | pub apb2lpenr: RW, 41 | _reserved6: [u8; 8usize], 42 | 43 | // 0x70 44 | pub bdcr: RW, 45 | pub csr: RW, 46 | _reserved7: [u8; 8usize], 47 | 48 | // 0x80 49 | pub sscgr: RW, 50 | pub plli2sr: RW, 51 | pub pllsaicfgr: RW, 52 | pub dckcfgr: RW, 53 | } 54 | 55 | pub struct Rcc { 56 | base: usize, 57 | } 58 | 59 | impl Rcc { 60 | pub const fn new(base: usize) -> Rcc { 61 | Rcc { base } 62 | } 63 | 64 | pub fn get_registers_ref(&self) -> &RccRegisters { 65 | let registers = self.base as *mut RccRegisters; 66 | unsafe { &*registers } 67 | } 68 | } 69 | 70 | pub static RCC: Rcc = Rcc::new(0x4002_3800); 71 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/serial.rs: -------------------------------------------------------------------------------- 1 | extern crate embedded_hal as hal; 2 | use crate::dma::{Client, DmaClient, Stream3}; 3 | use core::fmt::Debug; 4 | use vcell::VolatileCell; 5 | use volatile_register::RW; 6 | use core::fmt::Write; 7 | use hal::serial::Write as SerialWrite; 8 | 9 | pub struct Serial { 10 | usart: U, 11 | rx_dma: Rx, 12 | tx_dma: Tx, 13 | } 14 | 15 | pub enum Error { 16 | Overrun, 17 | } 18 | 19 | impl Debug for Error { 20 | fn fmt(&self, _: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { 21 | Ok(()) 22 | } 23 | } 24 | 25 | pub struct Usart { 26 | registers: *mut UsartRegisters, 27 | } 28 | 29 | #[repr(C)] 30 | pub struct UsartRegisters { 31 | sr: RW, 32 | dr: RW, 33 | brr: RW, 34 | cr1: RW, 35 | cr2: RW, 36 | cr3: RW, 37 | gtpr: RW, 38 | } 39 | 40 | impl Usart { 41 | pub fn new(base: usize) -> Usart { 42 | Usart { 43 | registers: base as *mut UsartRegisters, 44 | } 45 | } 46 | 47 | pub fn get_registers_ref(&self) -> &UsartRegisters { 48 | unsafe { &*self.registers } 49 | } 50 | } 51 | 52 | impl hal::serial::Read for Serial { 53 | type Error = Error; 54 | 55 | fn read(&mut self) -> nb::Result { 56 | let registers = self.usart.get_registers_ref(); 57 | 58 | while (registers.sr.read() & (1 << 5)) == 0 {} 59 | let c = registers.dr.read() as u8 as char; 60 | if c == '\r' { 61 | Ok('\n') 62 | } else { 63 | Ok(c) 64 | } 65 | } 66 | } 67 | 68 | impl SerialWrite for Serial { 69 | type Error = Error; 70 | 71 | fn write(&mut self, c: char) -> nb::Result<(), Error> { 72 | let registers = self.usart.get_registers_ref(); 73 | if c == '\n' { 74 | while (registers.sr.read() & (1 << 7)) == 0 {} 75 | unsafe { 76 | registers.dr.write('\r' as u32); 77 | } 78 | } 79 | while (registers.sr.read() & (1 << 7)) == 0 {} 80 | unsafe { 81 | registers.dr.write(c as u32); 82 | } 83 | Ok(()) 84 | } 85 | 86 | fn flush(&mut self) -> nb::Result<(), Error> { 87 | let registers = self.usart.get_registers_ref(); 88 | while (registers.sr.read() & (1 << 7)) == 0 {} 89 | Ok(()) 90 | } 91 | } 92 | 93 | impl Serial { 94 | pub fn usart3() -> Serial { 95 | // f = 16MHz, baud rate = 9600 BPS 96 | let usart = Usart::new(0x40004800); 97 | let registers = usart.get_registers_ref(); 98 | unsafe { 99 | registers.brr.write(0x683); 100 | registers 101 | .cr1 102 | .write((1 << 5) | (1 << 3) | (1 << 2) | (1 << 13)); 103 | } 104 | 105 | Serial { 106 | usart, 107 | rx_dma: (), 108 | tx_dma: (), 109 | } 110 | } 111 | } 112 | 113 | impl Write for Serial { 114 | fn write_str(&mut self, s: &str) -> core::fmt::Result { 115 | let _ = s 116 | .bytes() 117 | .map(|c| nb::block!(self.write(char::from(c)))) 118 | .last(); 119 | Ok(()) 120 | } 121 | } 122 | 123 | impl Serial> { 124 | pub fn usart3_tx_dma() -> Serial> { 125 | // f = 16MHz, baud rate = 9600 BPS 126 | let usart = Usart::new(0x40004800); 127 | let registers = usart.get_registers_ref(); 128 | unsafe { 129 | registers.brr.write(0x683); 130 | registers 131 | .cr1 132 | .write((1 << 5) | (1 << 3) | (1 << 2) | (1 << 13)); 133 | // enable transmitter DMA 134 | registers.cr3.modify(|v| v | (1 << 7)); 135 | } 136 | 137 | let tx_dma = DmaClient::dma1_stream3(); 138 | 139 | Serial { 140 | usart, 141 | rx_dma: (), 142 | tx_dma, 143 | } 144 | } 145 | 146 | pub fn send_buffer(&self, buffer: &'static [u8]) { 147 | let registers = self.usart.get_registers_ref(); 148 | unsafe { 149 | // clear tc 150 | registers.sr.modify(|r| r & !(1 << 6)); 151 | } 152 | self.tx_dma.transfer(buffer, 0x40004800 + 0x04, 0x04) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /devices/stm32f429zi/src/syscfg.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | use volatile_register::RW; 3 | 4 | #[repr(C)] 5 | pub struct SyscfgRegisters { 6 | pub memrmp: RW, 7 | pub pmc: RW, 8 | pub exticr1: RW, 9 | pub exticr2: RW, 10 | pub exticr3: RW, 11 | pub exticr4: RW, 12 | _reserved: u32, 13 | pub cmpcr: RW, 14 | } 15 | 16 | pub struct Syscfg { 17 | base: u32, 18 | } 19 | 20 | impl Deref for Syscfg { 21 | type Target = SyscfgRegisters; 22 | 23 | fn deref(&self) -> &Self::Target { 24 | let registers = self.base as *mut SyscfgRegisters; 25 | unsafe { &*registers } 26 | } 27 | } 28 | 29 | impl Syscfg { 30 | pub const fn new(base: u32) -> Syscfg { 31 | Syscfg { base } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /devices/wio_terminal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wio_terminal" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | volatile-register = "0.2.0" 11 | -------------------------------------------------------------------------------- /devices/wio_terminal/build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, error::Error, fs::File, io::Write, path::PathBuf}; 2 | 3 | fn main() -> Result<(), Box> { 4 | // Put the linker script somewhere the linker can find it 5 | let out = PathBuf::from(env::var("OUT_DIR")?); 6 | 7 | File::create(out.join("device.ld"))?.write_all(include_bytes!("device.ld"))?; 8 | 9 | println!("cargo:rustc-link-search={}", out.display()); 10 | 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /devices/wio_terminal/device.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH : ORIGIN = 0x00000000 + 16K, LENGTH = 512K - 16K 4 | RAM : ORIGIN = 0x20000000, LENGTH = 192K 5 | } 6 | -------------------------------------------------------------------------------- /devices/wio_terminal/src/button.rs: -------------------------------------------------------------------------------- 1 | use crate::pin::Pin; 2 | use crate::port::PortC; 3 | 4 | pub struct Button<'a, P> { 5 | pin: &'a P 6 | } 7 | 8 | type PC26<'a> = Pin<'a, PortC, 26>; 9 | type PC27<'a> = Pin<'a, PortC, 27>; 10 | type PC28<'a> = Pin<'a, PortC, 28>; 11 | 12 | pub type UserButton1<'a> = Button<'a, PC26<'a>>; 13 | pub type UserButton2<'a> = Button<'a, PC27<'a>>; 14 | pub type UserButton3<'a> = Button<'a, PC28<'a>>; 15 | 16 | impl<'a> Button<'a, PC26<'a>> { 17 | pub fn init(pin: &'a PC26) -> Self { 18 | pin.clear_dir(); 19 | pin.pincfg().set_inen(); 20 | pin.pincfg().set_pullen(); 21 | Self { pin } 22 | } 23 | 24 | pub fn is_pressed(&self) -> bool { 25 | !self.pin.in_() 26 | } 27 | 28 | pub fn is_released(&self) -> bool { 29 | self.pin.in_() 30 | } 31 | } 32 | 33 | impl<'a> Button<'a, PC27<'a>> { 34 | pub fn init(pin: &'a PC27) -> Self { 35 | pin.clear_dir(); 36 | pin.pincfg().set_inen(); 37 | pin.pincfg().set_pullen(); 38 | Self { pin } 39 | } 40 | } 41 | 42 | impl<'a> Button<'a, PC28<'a>> { 43 | pub fn init(pin: &'a PC28) -> Self { 44 | pin.clear_dir(); 45 | pin.pincfg().set_inen(); 46 | pin.pincfg().set_pullen(); 47 | Self { pin } 48 | } 49 | } -------------------------------------------------------------------------------- /devices/wio_terminal/src/generic_clock.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | use volatile_register::RW; 3 | 4 | #[repr(C)] 5 | pub struct GenericClocksRegisters { 6 | pub ctrla: RW, 7 | _reserved: [u8; 3], 8 | pub syncbusy: RW, 9 | _reserved1: [u32; 2], 10 | 11 | _reserved2: [u32; 4], 12 | 13 | pub genctrl: [RW; 12], 14 | 15 | _reserved3: [u32; 12], 16 | 17 | pub pchctrl: [RW; 48], 18 | } 19 | 20 | pub struct GenericClocks {} 21 | 22 | impl Deref for GenericClocks { 23 | type Target = GenericClocksRegisters; 24 | 25 | fn deref(&self) -> &Self::Target { 26 | let registers = 0x4000_1c00 as *mut GenericClocksRegisters; 27 | unsafe { &*registers } 28 | } 29 | } 30 | 31 | pub struct GenericClock<'a, const N: u8> { 32 | clocks: &'a GenericClocks, 33 | } 34 | 35 | impl<'a, const N: u8> GenericClock<'a, N> { 36 | pub fn init(clocks: &GenericClocks) -> Self { 37 | clocks.genctrl[N].modify(|v| (v & !(0xffff << 16)) | (1 << 8)); 38 | Self { 39 | clocks 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /devices/wio_terminal/src/irq.rs: -------------------------------------------------------------------------------- 1 | use rt::Vector; 2 | 3 | #[link_section = ".irq_table"] 4 | #[used] 5 | #[no_mangle] 6 | pub static mut IRQS: [Vector; 137] = [Vector { reserved: 0 }; 137]; 7 | -------------------------------------------------------------------------------- /devices/wio_terminal/src/led.rs: -------------------------------------------------------------------------------- 1 | use crate::port::{Port, PortA}; 2 | 3 | pub struct Led<'a, T> { 4 | port: &'a Port 5 | } 6 | 7 | pub type UserLed<'a> = Led<'a, PortA>; 8 | 9 | impl<'a> Led<'a, PortA> { 10 | pub fn init(port: &'a Port) -> Self { 11 | unsafe { 12 | port.dir.modify(|val| val | (1 << 15)); 13 | } 14 | port.pincfg[15].set_pullen(); 15 | Led { 16 | port, 17 | } 18 | } 19 | 20 | pub fn set(&self) { 21 | unsafe { 22 | self.port.outset.write(1 << 15); 23 | } 24 | } 25 | 26 | pub fn clear(&self) { 27 | unsafe { 28 | self.port.outclr.write(1 << 15); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /devices/wio_terminal/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(asm)] 3 | 4 | pub mod button; 5 | pub mod pin; 6 | pub mod port; 7 | pub mod led; -------------------------------------------------------------------------------- /devices/wio_terminal/src/pin.rs: -------------------------------------------------------------------------------- 1 | use crate::port::{Port, PortC, PinCfg}; 2 | 3 | pub struct Pin<'a, P, const N: u8> { 4 | port: &'a Port

, 5 | } 6 | 7 | impl<'a, const N: u8> Pin<'a, PortC, N> { 8 | pub fn new(port: &'a Port) -> Self { 9 | Self { 10 | port, 11 | } 12 | } 13 | 14 | pub fn clear_dir(&self) { 15 | unsafe { 16 | self.port.dirclr.write(1 << N); 17 | } 18 | } 19 | 20 | pub fn set_dir(&self) { 21 | unsafe { 22 | self.port.dirset.write(1 << N); 23 | } 24 | } 25 | 26 | pub fn in_(&self) -> bool { 27 | (self.port.in_.read() & (1 << N)) > 0 28 | } 29 | 30 | pub fn pincfg(&self) -> &PinCfg { 31 | &self.port.pincfg[N as usize] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /devices/wio_terminal/src/port.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | use core::marker::PhantomData; 3 | use volatile_register::RW; 4 | 5 | #[repr(C)] 6 | pub struct PortRegisters { 7 | pub dir: RW, 8 | pub dirclr: RW, 9 | pub dirset: RW, 10 | pub dirtgl: RW, 11 | 12 | pub out: RW, 13 | pub outclr: RW, 14 | pub outset: RW, 15 | pub outtgl: RW, 16 | 17 | pub in_:RW, 18 | pub ctrl: RW, 19 | pub wrconfigf: RW, 20 | pub evctrl: RW, 21 | 22 | pub pmux: [RW; 16], 23 | 24 | pub pincfg: [PinCfg; 32], 25 | } 26 | 27 | #[repr(transparent)] 28 | pub struct PinCfg { 29 | reg: RW, 30 | } 31 | 32 | impl PinCfg { 33 | pub fn set_pmuxen(&self) { 34 | unsafe { 35 | self.reg.modify(|r| r | 1); 36 | } 37 | } 38 | pub fn set_inen(&self) { 39 | unsafe { 40 | self.reg.modify(|r| r | (1 << 1)); 41 | } 42 | } 43 | pub fn set_pullen(&self) { 44 | unsafe{ 45 | self.reg.modify(|r| r | (1 << 2)); 46 | } 47 | } 48 | pub fn set_drvstr(&self) { 49 | unsafe{ 50 | self.reg.modify(|r| r | (1 << 6)); 51 | } 52 | } 53 | } 54 | 55 | pub struct Port { 56 | _marker: PhantomData, 57 | } 58 | 59 | impl Port { 60 | pub fn new() -> Self { 61 | Port { 62 | _marker: PhantomData, 63 | } 64 | } 65 | } 66 | 67 | pub enum PortA {} 68 | pub enum PortB {} 69 | pub enum PortC {} 70 | pub enum PortD {} 71 | 72 | impl Deref for Port { 73 | type Target = PortRegisters; 74 | 75 | fn deref(&self) -> &Self::Target { 76 | let registers = 0x4100_8000 as *mut PortRegisters; 77 | unsafe { &*registers } 78 | } 79 | } 80 | 81 | impl Deref for Port { 82 | type Target = PortRegisters; 83 | 84 | fn deref(&self) -> &Self::Target { 85 | let registers = 0x4100_8080 as *mut PortRegisters; 86 | unsafe { &*registers } 87 | } 88 | } 89 | 90 | impl Deref for Port { 91 | type Target = PortRegisters; 92 | 93 | fn deref(&self) -> &Self::Target { 94 | let registers = 0x4100_8100 as *mut PortRegisters; 95 | unsafe { &*registers } 96 | } 97 | } 98 | 99 | impl Deref for Port { 100 | type Target = PortRegisters; 101 | 102 | fn deref(&self) -> &Self::Target { 103 | let registers = 0x4100_8180 as *mut PortRegisters; 104 | unsafe { &*registers } 105 | } 106 | } -------------------------------------------------------------------------------- /kernel/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /kernel/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aligned" 5 | version = "0.3.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "as-slice" 13 | version = "0.1.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 18 | ] 19 | 20 | [[package]] 21 | name = "bare-metal" 22 | version = "0.2.4" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | dependencies = [ 25 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "cortex-m" 30 | version = "0.6.0" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | dependencies = [ 33 | "aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 36 | ] 37 | 38 | [[package]] 39 | name = "cortex-m-semihosting" 40 | version = "0.3.3" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | dependencies = [ 43 | "cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 44 | ] 45 | 46 | [[package]] 47 | name = "device" 48 | version = "0.1.0" 49 | dependencies = [ 50 | "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 51 | "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "rt 0.1.0", 53 | "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 54 | "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 55 | ] 56 | 57 | [[package]] 58 | name = "embedded-hal" 59 | version = "0.2.3" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | dependencies = [ 62 | "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 63 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 64 | ] 65 | 66 | [[package]] 67 | name = "generic-array" 68 | version = "0.12.0" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | dependencies = [ 71 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 72 | ] 73 | 74 | [[package]] 75 | name = "kernel" 76 | version = "0.1.0" 77 | dependencies = [ 78 | "device 0.1.0", 79 | "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 80 | "rt 0.1.0", 81 | ] 82 | 83 | [[package]] 84 | name = "nb" 85 | version = "0.1.2" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | 88 | [[package]] 89 | name = "rt" 90 | version = "0.1.0" 91 | dependencies = [ 92 | "cortex-m-semihosting 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 93 | ] 94 | 95 | [[package]] 96 | name = "rustc_version" 97 | version = "0.2.3" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | dependencies = [ 100 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 101 | ] 102 | 103 | [[package]] 104 | name = "semver" 105 | version = "0.9.0" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | dependencies = [ 108 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 109 | ] 110 | 111 | [[package]] 112 | name = "semver-parser" 113 | version = "0.7.0" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | 116 | [[package]] 117 | name = "stable_deref_trait" 118 | version = "1.1.1" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | 121 | [[package]] 122 | name = "typenum" 123 | version = "1.10.0" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | 126 | [[package]] 127 | name = "vcell" 128 | version = "0.1.0" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | 131 | [[package]] 132 | name = "void" 133 | version = "1.0.2" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | 136 | [[package]] 137 | name = "volatile-register" 138 | version = "0.2.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | dependencies = [ 141 | "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 142 | ] 143 | 144 | [metadata] 145 | "checksum aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a316c7ea8e1e9ece54862c992def5a7ac14de9f5832b69d71760680efeeefa" 146 | "checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27" 147 | "checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a" 148 | "checksum cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3c18719fdc57db65668bfc977db9a0fa1a41d718c5d9cd4f652c9d4b0e0956a" 149 | "checksum cortex-m-semihosting 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "165f3f86f4d1031351a6c9dc8d5a3f8fae2050f9dd6ef925e3d675c232cc0e46" 150 | "checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b" 151 | "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" 152 | "checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc" 153 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 154 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 155 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 156 | "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 157 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 158 | "checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" 159 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 160 | "checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" 161 | -------------------------------------------------------------------------------- /kernel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | arch = { path = "../arch" } 9 | util = { path = "../util" } 10 | rt = { path = "../rt" } 11 | log = { path = "../log" } 12 | embedded-hal = "0.2.2" 13 | cortex-m-semihosting = "0.3.2" 14 | [build-dependencies] 15 | cc = "1.0" -------------------------------------------------------------------------------- /kernel/build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, error::Error, path::PathBuf}; 2 | use cc::Build; 3 | 4 | fn main() -> Result<(), Box> { 5 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); 6 | 7 | println!("cargo:rustc-link-search={}", out_dir.display()); 8 | 9 | // `asm.s`ファイルをアセンブルします 10 | Build::new().file("src/asm.s").compile("asm"); 11 | 12 | Ok(()) 13 | } -------------------------------------------------------------------------------- /kernel/src/asm.s: -------------------------------------------------------------------------------- 1 | .cpu cortex-m4 2 | .thumb 3 | 4 | .section .text 5 | .syntax unified 6 | .global asm_execute_process 7 | 8 | asm_execute_process: 9 | push {r4, r5, r6, r7, lr} 10 | push {r8, r9, r10, r11} 11 | msr psp, r0 12 | ldmia r1, {r4-r11} 13 | cpsie i 14 | svc 0 15 | cpsid i 16 | stmia r1, {r4-r11} 17 | mrs r0, psp 18 | pop {r8, r9, r10, r11} 19 | pop {r4, r5, r6, r7, pc} 20 | -------------------------------------------------------------------------------- /kernel/src/interrupt_manager.rs: -------------------------------------------------------------------------------- 1 | use crate::process_list::{ProcessList, ProcessListItem}; 2 | use arch::nvic::Nvic; 3 | use core::mem; 4 | use rt::Vector; 5 | 6 | extern "C" { 7 | static mut IRQS: [Vector; 240]; 8 | } 9 | 10 | struct InterruptHandler<'a> { 11 | id: u32, 12 | func: fn(), 13 | waiting: ProcessList<'a>, 14 | } 15 | 16 | // TODO: remove dependency on nvic 17 | pub struct InterruptManager<'a> { 18 | nvic: Nvic, 19 | // TODO: variable length 20 | handlers: [InterruptHandler<'a>; 10], 21 | handler_count: usize, 22 | } 23 | 24 | impl<'a> InterruptManager<'a> { 25 | pub fn create(nvic: Nvic) -> InterruptManager<'a> { 26 | unsafe { 27 | InterruptManager { 28 | nvic, 29 | handlers: mem::uninitialized(), 30 | handler_count: 0, 31 | } 32 | } 33 | } 34 | 35 | pub fn register(&mut self, id: u32, func: fn()) { 36 | if self.handler_count >= 10 { 37 | panic!("limit exceed"); 38 | } 39 | unsafe { 40 | IRQS[id as usize] = Vector { 41 | handler: DefaultIrqHandler, 42 | }; 43 | } 44 | self.nvic.enable(id); 45 | self.handlers[self.handler_count] = InterruptHandler { 46 | id, 47 | func, 48 | waiting: ProcessList::new(), 49 | }; 50 | self.handler_count += 1; 51 | } 52 | 53 | pub fn push_wait(&mut self, tar_id: u32, item: &'a mut ProcessListItem<'a>) { 54 | for i in 0..self.handler_count { 55 | let id = self.handlers[i].id; 56 | if id == tar_id { 57 | self.handlers[i].waiting.push(item); 58 | return; 59 | } 60 | } 61 | panic!("no handler"); 62 | } 63 | 64 | pub fn check_pending(&mut self) -> ProcessList<'a> { 65 | let mut process_list = ProcessList::new(); 66 | for i in 0..self.handler_count { 67 | let id = self.handlers[i].id as u32; 68 | if self.nvic.is_pending(id) { 69 | (self.handlers[i].func)(); 70 | process_list.join(&mut self.handlers[i].waiting); 71 | self.nvic.clear_pending(id); 72 | self.nvic.enable(id); 73 | } 74 | } 75 | process_list 76 | } 77 | } 78 | 79 | #[naked] 80 | pub unsafe extern "C" fn DefaultIrqHandler() { 81 | asm!( 82 | "movw lr, #0xfff9", 83 | "movt lr, #0xffff", 84 | "mrs r0, IPSR", 85 | "and r0, #0xff", 86 | "sub r0, #16", 87 | "lsrs r1, r0, #5", 88 | "movs r3, #1", 89 | "and r0, r0, #31", 90 | "lsl r0, r3, r0", 91 | "mov r2, #0xe180", 92 | "movt r2, #0xe000", 93 | "str r0, [r2, r1, lsl #2]", 94 | "bx lr", 95 | options(noreturn), 96 | ); 97 | } 98 | -------------------------------------------------------------------------------- /kernel/src/kernel.rs: -------------------------------------------------------------------------------- 1 | use crate::interrupt_manager::InterruptManager; 2 | use crate::message_manager::MessageManager; 3 | use crate::process::Process; 4 | use crate::process_manager::{ProcessId, ProcessManager}; 5 | use crate::scheduler::Scheduler; 6 | use crate::syscall_id; 7 | use arch::StackFrame; 8 | use core::cell::RefCell; 9 | use core::slice::from_raw_parts; 10 | use embedded_hal::serial::Write; 11 | use log::dhprintln; 12 | use rt::SYSCALL_FIRED; 13 | 14 | pub struct Kernel<'a, S, W> { 15 | scheduler: RefCell, 16 | interrupt_manager: InterruptManager<'a>, 17 | serial: RefCell, 18 | process_manager: ProcessManager<'a, Process<'a>>, 19 | // process_manager: RefCell>>, 20 | message_manager: RefCell>, 21 | //message_manager: MessageManager<'a>, 22 | } 23 | 24 | impl<'a, S, W> Kernel<'a, S, W> 25 | where 26 | S: Scheduler<'a>, 27 | W: Write, 28 | { 29 | pub fn create( 30 | scheduler: S, 31 | serial: W, 32 | interrupt_manager: InterruptManager<'a>, 33 | process_manager: ProcessManager<'a, Process<'a>>, 34 | message_manager: MessageManager<'a>, 35 | ) -> Kernel<'a, S, W> { 36 | Kernel { 37 | scheduler: RefCell::new(scheduler), 38 | serial: RefCell::new(serial), 39 | interrupt_manager, 40 | process_manager, 41 | //process_manager: RefCell::new(process_manager), 42 | message_manager: RefCell::new(message_manager), 43 | //message_manager, 44 | } 45 | } 46 | 47 | pub fn run(&'a mut self) -> ! { 48 | unsafe { 49 | asm!("cpsid i", options(nomem, nostack)); 50 | } 51 | let interrupt_manager = &mut self.interrupt_manager; 52 | let process_manager = &mut self.process_manager; 53 | loop { 54 | let mut sched = self.scheduler.borrow_mut(); 55 | let mut serial = self.serial.borrow_mut(); 56 | let mut message_manager = self.message_manager.borrow_mut(); 57 | //let mut process_manager = self.process_manager.borrow_mut(); 58 | let current_id: Option<&mut ProcessId> = sched.get_current_proc(); 59 | let mut should_schedule_next = false; 60 | 61 | match current_id { 62 | Some(item) => { 63 | let mut syscall: Option<*const u32> = None; 64 | process_manager.get_mut(item).map(|process| { 65 | process.execute(); 66 | unsafe { 67 | if SYSCALL_FIRED > 0 { 68 | syscall.replace(process.sp as *const u32); 69 | SYSCALL_FIRED = 0; 70 | } 71 | } 72 | }); 73 | 74 | match syscall { 75 | Some(sp) => { 76 | let base_frame = unsafe { StackFrame::from_ptr_mut(sp) }; 77 | let svc_id = base_frame.r0; 78 | match svc_id { 79 | syscall_id::PRINT => { 80 | let arg2 = base_frame.r2 as usize; 81 | let arg1 = 82 | unsafe { from_raw_parts(base_frame.r1 as *const u8, arg2) }; 83 | 84 | for i in 0..arg2 { 85 | let _ = serial.write(arg1[i] as char); 86 | } 87 | } 88 | syscall_id::YIELD => { 89 | should_schedule_next = true; 90 | } 91 | syscall_id::WAIT_IRQ => { 92 | let arg1 = base_frame.r1; 93 | interrupt_manager 94 | .push_wait(arg1, sched.pop_current_proc().unwrap()); 95 | } 96 | syscall_id::WAIT_SYSTICK => { 97 | let current = sched.pop_current_proc().unwrap(); 98 | sched.push_wait(current); 99 | } 100 | syscall_id::DORMANT => { 101 | sched.pop_current_proc().unwrap(); 102 | } 103 | syscall_id::SEND_MESSAGE => { 104 | let arg1 = base_frame.r1; 105 | let arg2 = base_frame.r2; 106 | let target = process_manager.borrow_mut(&ProcessId(arg1)); 107 | if target.is_none() { 108 | base_frame.r0 = 0; 109 | } else { 110 | let result = 111 | message_manager.send_message(target.unwrap(), arg2); 112 | base_frame.r0 = result.clone() as u32; 113 | } 114 | } 115 | syscall_id::RECEIVE_MESSAGE => { 116 | let result = message_manager 117 | .receive_message(process_manager.borrow_mut(item).unwrap()); 118 | if result.is_none() { 119 | base_frame.r0 = 0; 120 | } else { 121 | base_frame.r0 = 1; 122 | base_frame.r1 = result.unwrap().clone(); 123 | } 124 | } 125 | _ => { 126 | // TODO: error handling 127 | panic!("unknown svc"); 128 | } 129 | } 130 | } 131 | None => {} 132 | } 133 | } 134 | None => { 135 | dhprintln!("sleeping"); 136 | unsafe { 137 | asm!( 138 | "cpsie i", 139 | "wfi", 140 | "cpsid i", 141 | ); 142 | } 143 | } 144 | } 145 | 146 | let mut released_list = interrupt_manager.check_pending(); 147 | sched.resume_list(&mut released_list); 148 | 149 | if unsafe { SHOULD_DISPATCH } > 0 { 150 | sched.resume_waiting(); 151 | sched.schedule_next(); 152 | unsafe { SHOULD_DISPATCH = 0 }; 153 | } else if should_schedule_next { 154 | sched.schedule_next(); 155 | } 156 | } 157 | } 158 | } 159 | 160 | #[no_mangle] 161 | pub static mut SHOULD_DISPATCH: u32 = 0; 162 | 163 | #[no_mangle] 164 | pub unsafe extern "C" fn SysTick() { 165 | asm!( 166 | "movw lr, #0xfff9", 167 | "movt lr, #0xffff", 168 | "ldr r0, =SHOULD_DISPATCH", 169 | "mov r1, #1", 170 | "str r1, [r0, #0]", 171 | options(nostack), 172 | ); 173 | } 174 | -------------------------------------------------------------------------------- /kernel/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![crate_type = "rlib"] 3 | #![feature(asm)] 4 | #![feature(naked_functions)] 5 | 6 | pub mod interrupt_manager; 7 | pub mod kernel; 8 | pub mod macros; 9 | pub mod message_manager; 10 | pub mod process; 11 | pub mod process_list; 12 | pub mod process_manager; 13 | pub mod scheduler; 14 | pub mod syscall_id; 15 | -------------------------------------------------------------------------------- /kernel/src/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! stack_allocate { 3 | ($n:expr) => {{ 4 | #[link_section = ".uninit"] 5 | static mut STACK: [u8; $n] = [0; $n]; 6 | 7 | unsafe { &STACK[0] as *const u8 as u32 + $n } 8 | }}; 9 | } 10 | 11 | #[macro_export] 12 | macro_rules! reg_allocate { 13 | () => {{ 14 | static mut REGS: [u32; 8] = [0; 8]; 15 | 16 | unsafe { &mut REGS } 17 | }}; 18 | } 19 | 20 | #[macro_export] 21 | macro_rules! process_create { 22 | ($entry:expr,$n:expr) => {{ 23 | let entry = $entry as u32; 24 | let sp = $crate::stack_allocate!($n); 25 | let regs = $crate::reg_allocate!(); 26 | Process::create(entry, sp, regs) 27 | }}; 28 | } 29 | 30 | #[macro_export] 31 | macro_rules! process_register { 32 | ($scheduler:expr,$process_manager:expr,$process:expr) => { 33 | let mut node = util::avl_tree::Node::new($crate::process_manager::ProcessId(0), $process); 34 | let id = $process_manager.register(&mut node); 35 | let mut item = $crate::process_list::ProcessListItem::create(id); 36 | $scheduler.push(&mut item); 37 | }; 38 | ($scheduler:expr,$process_manager:expr,$process:expr,$id:ident) => { 39 | let mut node = util::avl_tree::Node::new($crate::process_manager::ProcessId(0), $process); 40 | let id = $process_manager.register(&mut node); 41 | let $id = id.0; 42 | let mut item = $crate::process_list::ProcessListItem::create(id); 43 | $scheduler.push(&mut item); 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /kernel/src/message_manager.rs: -------------------------------------------------------------------------------- 1 | use crate::process::Process; 2 | use util::linked_list::{LinkedList, ListItem}; 3 | 4 | pub struct MessageManager<'a> { 5 | buff: LinkedList<'a, u32>, 6 | } 7 | 8 | impl<'a> MessageManager<'a> { 9 | pub fn new(buff: &'a mut [ListItem<'a, u32>]) -> MessageManager<'a> { 10 | let mut list = LinkedList::new(); 11 | for item in buff.iter_mut() { 12 | list.push(item); 13 | } 14 | 15 | MessageManager { buff: list } 16 | } 17 | 18 | pub fn send_message(&mut self, process: &'a mut Process<'a>, message: u32) -> bool { 19 | if self.buff.is_empty() { 20 | return false; 21 | } 22 | 23 | let mut item = self.buff.pop().unwrap(); 24 | item.item = message; 25 | process.message_queue.push(item); 26 | 27 | true 28 | } 29 | 30 | pub fn receive_message(&mut self, process: &'a mut Process<'a>) -> Option { 31 | if process.message_queue.is_empty() { 32 | return None; 33 | } 34 | 35 | let item = process.message_queue.pop().unwrap(); 36 | let result = Some(item.item); 37 | 38 | self.buff.push(item); 39 | 40 | result 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /kernel/src/process.rs: -------------------------------------------------------------------------------- 1 | use core::slice::from_raw_parts_mut; 2 | use util::linked_list::LinkedList; 3 | 4 | #[derive(PartialEq)] 5 | pub enum ProcessState { 6 | READY, 7 | RUNNING, 8 | WAITING, 9 | DORMANT, 10 | } 11 | 12 | pub struct Process<'a> { 13 | pub sp: *mut u8, 14 | pub regs: &'a mut [u32; 8], 15 | pub state: ProcessState, 16 | pub message_queue: LinkedList<'a, u32>, 17 | } 18 | 19 | extern "C" { 20 | fn asm_execute_process(sp: *mut u8, regs: &mut [u32; 8]) -> *mut u8; 21 | } 22 | 23 | impl<'a> Process<'a> { 24 | pub fn create(entry: u32, sp: u32, regs: &'a mut [u32; 8]) -> Process { 25 | let base_frame_ptr = (sp - 0x20) as *mut u32; 26 | let base_frame = unsafe { from_raw_parts_mut(base_frame_ptr, 8) }; 27 | base_frame[0] = 0; // r0 28 | base_frame[1] = 0; // r1 29 | base_frame[2] = 0; // r2 30 | base_frame[3] = 0; // r3 31 | base_frame[4] = 0; // r12 32 | base_frame[5] = 0; // lr(r14) 33 | base_frame[6] = entry & !1; // return address 34 | base_frame[7] = 0x01000000; // xpsr, set thumb state 35 | Process { 36 | sp: base_frame_ptr as *mut u8, 37 | regs: regs, 38 | state: ProcessState::DORMANT, 39 | message_queue: LinkedList::new(), 40 | } 41 | } 42 | 43 | pub fn execute(&mut self) { 44 | self.sp = unsafe { asm_execute_process(self.sp, self.regs) }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /kernel/src/process_list.rs: -------------------------------------------------------------------------------- 1 | use crate::process_manager::ProcessId; 2 | use util::linked_list::{LinkedList, ListItem}; 3 | 4 | pub type ProcessListItem<'a> = ListItem<'a, ProcessId>; 5 | pub type ProcessList<'a> = LinkedList<'a, ProcessId>; 6 | -------------------------------------------------------------------------------- /kernel/src/process_manager.rs: -------------------------------------------------------------------------------- 1 | use util::avl_tree::{AvlTree, Node}; 2 | use util::binary_tree::BinaryTree; 3 | 4 | #[derive(PartialOrd, PartialEq, Eq, Ord, Clone)] 5 | pub struct ProcessId(pub u32); 6 | 7 | pub struct ProcessManager<'a, P> { 8 | map: AvlTree<'a, ProcessId, P>, 9 | count: u32, 10 | } 11 | 12 | impl<'a, P> ProcessManager<'a, P> { 13 | pub fn new() -> ProcessManager<'a, P> { 14 | ProcessManager { 15 | map: AvlTree::new(), 16 | count: 0, 17 | } 18 | } 19 | 20 | pub fn register(&mut self, node: &'a mut Node<'a, ProcessId, P>) -> ProcessId { 21 | let id = ProcessId(self.count); 22 | node.item.0 = id.clone(); 23 | self.map.insert(node); 24 | self.count += 1; 25 | id 26 | } 27 | 28 | pub fn get(&self, id: &ProcessId) -> Option<&P> { 29 | self.map.get(id) 30 | } 31 | 32 | pub fn borrow(&self, id: &ProcessId) -> Option<&'a P> { 33 | self.map.borrow(id) 34 | } 35 | 36 | pub fn get_mut(&mut self, id: &ProcessId) -> Option<&mut P> { 37 | self.map.get_mut(id) 38 | } 39 | 40 | pub fn borrow_mut(&mut self, id: &ProcessId) -> Option<&'a mut P> { 41 | self.map.borrow_mut(id) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /kernel/src/scheduler.rs: -------------------------------------------------------------------------------- 1 | use crate::process_list::{ProcessList, ProcessListItem}; 2 | use crate::process_manager::ProcessId; 3 | 4 | pub mod simple_scheduler; 5 | 6 | pub trait Scheduler<'a> { 7 | fn get_current_proc(&mut self) -> Option<&mut ProcessId>; 8 | fn pop_current_proc(&mut self) -> Option<&'a mut ProcessListItem<'a>>; 9 | fn schedule_next(&mut self); 10 | fn resume_list(&mut self, process_list: &mut ProcessList<'a>); 11 | fn push(&mut self, proc: &'a mut ProcessListItem<'a>); 12 | fn push_wait(&mut self, proc: &'a mut ProcessListItem<'a>); 13 | fn resume_waiting(&mut self); 14 | } 15 | 16 | pub enum ExecResult { 17 | Nothing, 18 | Executed, 19 | } 20 | -------------------------------------------------------------------------------- /kernel/src/scheduler/simple_scheduler.rs: -------------------------------------------------------------------------------- 1 | use core::ops::DerefMut; 2 | use core::option::Option; 3 | 4 | use super::{ExecResult, Scheduler}; 5 | use crate::process_list::ProcessListItem; 6 | use crate::process_manager::ProcessId; 7 | use util::linked_list::{LinkedList, ListItem}; 8 | 9 | pub struct SimpleScheduler<'a> { 10 | active: LinkedList<'a, ProcessId>, 11 | waiting: LinkedList<'a, ProcessId>, 12 | } 13 | 14 | impl<'a> Scheduler<'a> for SimpleScheduler<'a> { 15 | fn get_current_proc(&mut self) -> Option<&mut ProcessId> { 16 | self.active.head_mut().map(|item| (*item).deref_mut()) 17 | } 18 | 19 | fn pop_current_proc(&mut self) -> Option<&'a mut ProcessListItem<'a>> { 20 | self.active.pop() 21 | } 22 | 23 | fn schedule_next(&mut self) { 24 | if !self.active.is_empty() { 25 | let current = self.active.pop().unwrap(); 26 | self.active.push(current); 27 | } 28 | } 29 | 30 | fn resume_list(&mut self, process_list: &mut LinkedList<'a, ProcessId>) { 31 | self.active.join(process_list); 32 | } 33 | 34 | fn push(&mut self, proc: &'a mut ListItem<'a, ProcessId>) { 35 | self.active.push(proc); 36 | } 37 | 38 | fn push_wait(&mut self, proc: &'a mut ListItem<'a, ProcessId>) { 39 | self.waiting.push(proc); 40 | } 41 | 42 | fn resume_waiting(&mut self) { 43 | self.active.join(&mut self.waiting); 44 | } 45 | } 46 | 47 | impl<'a> SimpleScheduler<'a> { 48 | pub fn new() -> SimpleScheduler<'a> { 49 | SimpleScheduler { 50 | active: LinkedList::new(), 51 | waiting: LinkedList::new(), 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /kernel/src/syscall_id.rs: -------------------------------------------------------------------------------- 1 | pub const PRINT: u32 = 1; 2 | pub const YIELD: u32 = 2; 3 | pub const WAIT_IRQ: u32 = 3; 4 | pub const WAIT_SYSTICK: u32 = 4; 5 | pub const DORMANT: u32 = 5; 6 | pub const SEND_MESSAGE: u32 = 6; 7 | pub const RECEIVE_MESSAGE: u32 = 7; 8 | -------------------------------------------------------------------------------- /log/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock -------------------------------------------------------------------------------- /log/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "log" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | cortex-m-semihosting = "0.3.5" -------------------------------------------------------------------------------- /log/build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, error::Error, fs::File, io::Write, path::PathBuf}; 2 | 3 | fn main() -> Result<(), Box> { 4 | // Put the linker script somewhere the linker can find it 5 | let out = PathBuf::from(env::var("OUT_DIR")?); 6 | 7 | File::create(out.join("log.ld"))?.write_all(include_bytes!("log.ld"))?; 8 | 9 | println!("cargo:rustc-link-search={}", out.display()); 10 | 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /log/log.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | .log 0 (INFO) : { 4 | *(.log); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /log/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub trait Log { 4 | type Error; 5 | 6 | fn log(&mut self, address: u8) -> Result<(), Self::Error>; 7 | } 8 | 9 | #[macro_export] 10 | macro_rules! log { 11 | ($logger:expr, $string:expr) => {{ 12 | #[export_name = $string] 13 | #[link_section = ".log"] 14 | static SYMBOL: u8 = 0; 15 | 16 | $crate::Log::log(&mut $logger, &SYMBOL as *const u8 as usize as u8) 17 | }}; 18 | } 19 | 20 | #[cfg(debug_assertions)] 21 | #[macro_export] 22 | macro_rules! debug { 23 | ($logger:expr, $string:expr) => {{ 24 | #[export_name = $string] 25 | #[link_section = ".log"] 26 | static SYMBOL: u8 = 0; 27 | 28 | $crate::Log::log(&mut $logger, &SYMBOL as *const u8 as usize as u8) 29 | }}; 30 | } 31 | 32 | #[cfg(not(debug_assertions))] 33 | #[macro_export] 34 | macro_rules! debug { 35 | ($logger:expr, $string:expr) => {{}}; 36 | } 37 | 38 | #[cfg(debug_assertions)] 39 | #[macro_export] 40 | macro_rules! dhprintln { 41 | () => { 42 | cortex_m_semihosting::hprintln!("\n").unwrap_or(()) 43 | }; 44 | ($s:expr) => { 45 | cortex_m_semihosting::hprintln!($s).unwrap_or(()) 46 | }; 47 | ($s:expr, $($tt:tt)*) => { 48 | cortex_m_semihosting::hprintln!($s, $($tt)*).unwrap_or(()) 49 | }; 50 | } 51 | 52 | #[cfg(not(debug_assertions))] 53 | #[macro_export] 54 | macro_rules! dhprintln { 55 | () => {}; 56 | ($s:expr) => {}; 57 | ($s:expr, $($tt:tt)*) => {}; 58 | } 59 | -------------------------------------------------------------------------------- /qemu-gnuarmeclipse.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | qemu_command=$HOME/opt/xPacks/@gnu-mcu-eclipse/qemu/2.8.0-5.1/.content/bin/qemu-system-gnuarmeclipse 4 | board_name=NUCLEO-F411RE 5 | mcu_name=STM32F411RE 6 | 7 | $qemu_command \ 8 | --verbose --verbose --board $board_name --gdb tcp::3333 \ 9 | --mcu $mcu_name -d unimp,guest_errors \ 10 | --image $1 \ 11 | -nographic \ 12 | --semihosting-config enable=on,target=native -------------------------------------------------------------------------------- /qemu_app/.cargo/config: -------------------------------------------------------------------------------- 1 | [target.thumbv7m-none-eabi] 2 | rustflags = [ 3 | "-C", "link-arg=-Tdevice.ld", 4 | "-C", "link-arg=-Tlink.ld", 5 | ] 6 | runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -d unimp,guest_errors -kernel" 7 | 8 | [build] 9 | target = "thumbv7m-none-eabi" 10 | -------------------------------------------------------------------------------- /qemu_app/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /qemu_app/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aligned" 5 | version = "0.3.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "arch" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 16 | ] 17 | 18 | [[package]] 19 | name = "as-slice" 20 | version = "0.1.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | dependencies = [ 23 | "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 25 | ] 26 | 27 | [[package]] 28 | name = "bare-metal" 29 | version = "0.2.4" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | dependencies = [ 32 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 33 | ] 34 | 35 | [[package]] 36 | name = "cortex-m" 37 | version = "0.6.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | dependencies = [ 40 | "aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 42 | "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 43 | ] 44 | 45 | [[package]] 46 | name = "cortex-m-semihosting" 47 | version = "0.3.3" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | dependencies = [ 50 | "cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 51 | ] 52 | 53 | [[package]] 54 | name = "embedded-hal" 55 | version = "0.2.3" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | dependencies = [ 58 | "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 59 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 60 | ] 61 | 62 | [[package]] 63 | name = "generic-array" 64 | version = "0.12.0" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | dependencies = [ 67 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 68 | ] 69 | 70 | [[package]] 71 | name = "kernel" 72 | version = "0.1.0" 73 | dependencies = [ 74 | "arch 0.1.0", 75 | "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 76 | "rt 0.1.0", 77 | "util 0.1.0", 78 | ] 79 | 80 | [[package]] 81 | name = "log" 82 | version = "0.1.0" 83 | 84 | [[package]] 85 | name = "nb" 86 | version = "0.1.2" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | 89 | [[package]] 90 | name = "qemu_app" 91 | version = "0.1.0" 92 | dependencies = [ 93 | "arch 0.1.0", 94 | "cortex-m-semihosting 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 96 | "kernel 0.1.0", 97 | "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 98 | "rt 0.1.0", 99 | ] 100 | 101 | [[package]] 102 | name = "rt" 103 | version = "0.1.0" 104 | dependencies = [ 105 | "cortex-m-semihosting 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 106 | "log 0.1.0", 107 | ] 108 | 109 | [[package]] 110 | name = "rustc_version" 111 | version = "0.2.3" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | dependencies = [ 114 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 115 | ] 116 | 117 | [[package]] 118 | name = "semver" 119 | version = "0.9.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | dependencies = [ 122 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 123 | ] 124 | 125 | [[package]] 126 | name = "semver-parser" 127 | version = "0.7.0" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | 130 | [[package]] 131 | name = "stable_deref_trait" 132 | version = "1.1.1" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | 135 | [[package]] 136 | name = "typenum" 137 | version = "1.10.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | 140 | [[package]] 141 | name = "util" 142 | version = "0.1.0" 143 | 144 | [[package]] 145 | name = "vcell" 146 | version = "0.1.0" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | 149 | [[package]] 150 | name = "void" 151 | version = "1.0.2" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | 154 | [[package]] 155 | name = "volatile-register" 156 | version = "0.2.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | dependencies = [ 159 | "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 160 | ] 161 | 162 | [metadata] 163 | "checksum aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a316c7ea8e1e9ece54862c992def5a7ac14de9f5832b69d71760680efeeefa" 164 | "checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27" 165 | "checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a" 166 | "checksum cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3c18719fdc57db65668bfc977db9a0fa1a41d718c5d9cd4f652c9d4b0e0956a" 167 | "checksum cortex-m-semihosting 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "165f3f86f4d1031351a6c9dc8d5a3f8fae2050f9dd6ef925e3d675c232cc0e46" 168 | "checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b" 169 | "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" 170 | "checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc" 171 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 172 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 173 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 174 | "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 175 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 176 | "checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" 177 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 178 | "checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" 179 | -------------------------------------------------------------------------------- /qemu_app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "qemu_app" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | arch = { path = "../arch" } 9 | rt = { path = "../rt" } 10 | kernel = { path = "../kernel" } 11 | util = { path = "../util" } 12 | log = { path = "../log" } 13 | user = { path = "../user" } 14 | cortex-m-semihosting = "0.3.2" 15 | embedded-hal = "0.2.2" 16 | nb = "0.1.2" 17 | -------------------------------------------------------------------------------- /qemu_app/build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, error::Error, fs::File, io::Write, path::PathBuf}; 2 | 3 | fn main() -> Result<(), Box> { 4 | // Put the linker script somewhere the linker can find it 5 | let out = PathBuf::from(env::var("OUT_DIR")?); 6 | 7 | File::create(out.join("device.ld"))?.write_all(include_bytes!("device.ld"))?; 8 | 9 | println!("cargo:rustc-link-search={}", out.display()); 10 | 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /qemu_app/device.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 256K 4 | RAM : ORIGIN = 0x20000000, LENGTH = 64K 5 | } 6 | -------------------------------------------------------------------------------- /qemu_app/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(asm)] 4 | 5 | use arch::nvic::Nvic; 6 | use core::fmt::Write as _; 7 | use core::marker::PhantomData; 8 | use cortex_m_semihosting::hio::HStdout; 9 | use cortex_m_semihosting::{debug, hio}; 10 | use embedded_hal::serial::Write; 11 | use kernel::interrupt_manager::InterruptManager; 12 | use kernel::kernel::Kernel; 13 | use kernel::message_manager::MessageManager; 14 | use kernel::process::Process; 15 | use kernel::process_list::ProcessListItem; 16 | use kernel::process_manager::{ProcessId, ProcessManager}; 17 | use kernel::scheduler::simple_scheduler::SimpleScheduler; 18 | use kernel::scheduler::Scheduler; 19 | use kernel::{process_create, process_register}; 20 | use log::dhprintln; 21 | use rt::entry; 22 | use rt::Vector; 23 | use user::syscall::{dormant, wait_for_event, wait_for_interrupt}; 24 | use util::avl_tree::Node; 25 | use util::linked_list::ListItem; 26 | 27 | entry!(main); 28 | #[link_section = ".irq_table"] 29 | #[used] 30 | #[no_mangle] 31 | pub static mut IRQS: [Vector; 1] = [ 32 | Vector { reserved: 0 }, // WWDG (0) 33 | ]; 34 | 35 | struct SemihostSerial { 36 | hstdout: HStdout, 37 | } 38 | 39 | impl Write for SemihostSerial { 40 | type Error = PhantomData; 41 | 42 | fn write(&mut self, c: char) -> nb::Result<(), Self::Error> { 43 | self.hstdout.write_all(&[c as u8]); 44 | Ok(()) 45 | } 46 | 47 | fn flush(&mut self) -> nb::Result<(), Self::Error> { 48 | Ok(()) 49 | } 50 | } 51 | 52 | fn main() -> ! { 53 | let mut hstdout = hio::hstdout().unwrap(); 54 | 55 | writeln!(hstdout, "hello world"); 56 | 57 | let nvic = Nvic::new(); 58 | 59 | let mut scheduler = SimpleScheduler::new(); 60 | let serial = SemihostSerial { hstdout }; 61 | let mut interrupt_manager = InterruptManager::create(nvic); 62 | let mut process_manager = ProcessManager::new(); 63 | let process = process_create!(app_main, 1024); 64 | let process2 = process_create!(app_main2, 1024); 65 | let process3 = process_create!(app_main3, 1024); 66 | let process4 = process_create!(app_main4, 1024); 67 | process_register!(scheduler, process_manager, process); 68 | process_register!(scheduler, process_manager, process2); 69 | process_register!(scheduler, process_manager, process3); 70 | process_register!(scheduler, process_manager, process4); 71 | interrupt_manager.register(0, nothing); 72 | 73 | let mut message_buff: [ListItem; 32] = unsafe { core::mem::uninitialized() }; 74 | let message_manager = MessageManager::new(&mut message_buff); 75 | let mut kernel = Kernel::create( 76 | scheduler, 77 | serial, 78 | interrupt_manager, 79 | process_manager, 80 | message_manager, 81 | ); 82 | 83 | kernel.run() 84 | } 85 | 86 | fn nothing() {} 87 | 88 | fn fib(n: usize) -> usize { 89 | dhprintln!("fib called"); 90 | if n <= 1 { 91 | 1 92 | } else { 93 | fib(n - 1) + fib(n - 2) 94 | } 95 | } 96 | 97 | extern "C" fn app_main() -> ! { 98 | let message: &str = "app_main\n"; 99 | let message_ptr = message.as_ptr(); 100 | let length = message.bytes().len(); 101 | dhprintln!("fib {}: {}", 5, fib(5)); 102 | unsafe { 103 | asm!( 104 | "mov r0, #1", 105 | "svc 1", 106 | out("r0") _, 107 | in("r1") message_ptr, 108 | in("r2") length 109 | ); 110 | } 111 | wait_for_event(); 112 | dhprintln!("fib {}: {}", 8, fib(8)); 113 | dormant(); 114 | loop {} 115 | } 116 | extern "C" fn app_main2() -> ! { 117 | dhprintln!("fib {}: {}", 6, fib(6)); 118 | wait_for_event(); 119 | dhprintln!("fib {}: {}", 9, fib(9)); 120 | wait_for_event(); 121 | debug::exit(debug::EXIT_SUCCESS); 122 | 123 | loop { 124 | dormant(); 125 | } 126 | } 127 | 128 | extern "C" fn app_main3() -> ! { 129 | dhprintln!("fib {}: {}", 7, fib(7)); 130 | wait_for_event(); 131 | dhprintln!("fib {}: {}", 10, fib(10)); 132 | loop { 133 | dormant(); 134 | } 135 | } 136 | 137 | extern "C" fn app_main4() -> ! { 138 | wait_for_interrupt(0); 139 | loop { 140 | dormant(); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /rt/.cargo/config: -------------------------------------------------------------------------------- 1 | [target.thumbv7em-none-eabihf] 2 | rustflags = ["-C", "link-arg=-Tlink.ld"] 3 | 4 | [target.thumbv7m-none-eabi] 5 | rustflags = ["-C", "link-arg=-Tlink.ld"] 6 | 7 | [build] 8 | target = "thumbv7m-none-eabi" 9 | -------------------------------------------------------------------------------- /rt/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /rt/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "rt" 3 | version = "0.1.0" 4 | 5 | -------------------------------------------------------------------------------- /rt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rt" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | cortex-m-semihosting = "0.3.5" 9 | log = { path = "../log" } 10 | -------------------------------------------------------------------------------- /rt/build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, error::Error, fs::File, io::Write, path::PathBuf}; 2 | 3 | fn main() -> Result<(), Box> { 4 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); 5 | 6 | println!("cargo:rustc-link-search={}", out_dir.display()); 7 | 8 | File::create(out_dir.join("link.ld"))?.write_all(include_bytes!("link.ld"))?; 9 | 10 | Ok(()) 11 | } 12 | -------------------------------------------------------------------------------- /rt/link.ld: -------------------------------------------------------------------------------- 1 | /* The entry point is the reset handler */ 2 | ENTRY(Reset); 3 | 4 | EXTERN(RESET_VECTOR); 5 | EXTERN(EXCEPTIONS); 6 | EXTERN(IRQS); 7 | 8 | SECTIONS 9 | { 10 | .vector_table ORIGIN(FLASH) : 11 | { 12 | /* First entry: initial Stack Pointer value */ 13 | LONG(ORIGIN(RAM) + LENGTH(RAM)); 14 | /* Second entry: reset vector */ 15 | KEEP(*(.vector_table.reset_vector)); 16 | KEEP(*(.vector_table.exceptions)); 17 | } > FLASH 18 | 19 | .text : 20 | { 21 | *(.text .text.*); 22 | } > FLASH 23 | 24 | .ARM.exidx ALIGN(4) : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > FLASH 25 | 26 | .rodata : 27 | { 28 | *(.rodata .rodata.*); 29 | } > FLASH 30 | 31 | _sivector_table = LOADADDR(.vector_table); 32 | 33 | .app_vector_table (NOLOAD) : { 34 | _svector_table = .; 35 | . = . + 0x40; 36 | _evector_table = .; 37 | _sirq_table = .; 38 | KEEP(*(.irq_table)); 39 | _eirq_table = .; 40 | } > RAM 41 | 42 | .bss (NOLOAD): 43 | { 44 | _sbss = .; 45 | *(.bss .bss.*); 46 | _ebss = .; 47 | } > RAM 48 | 49 | .data : AT(ADDR(.rodata) + SIZEOF(.rodata)) 50 | { 51 | _sdata = .; 52 | *(.data .data.*); 53 | _edata = .; 54 | } > RAM 55 | 56 | _sidata = LOADADDR(.data); 57 | 58 | .uninit ALIGN(0x10): 59 | { 60 | _suinit = .; 61 | *(.uninit .uninit.*); 62 | _euninit = .; 63 | } > RAM 64 | 65 | /DISCARD/ : 66 | { 67 | *(.ARM.exidx.*); 68 | } 69 | } 70 | 71 | PROVIDE(NMI = DefaultExceptionHandler); 72 | PROVIDE(HardFault = DefaultExceptionHandler); 73 | PROVIDE(MemManage = DefaultExceptionHandler); 74 | PROVIDE(BusFault = DefaultExceptionHandler); 75 | PROVIDE(UsageFault = DefaultExceptionHandler); 76 | PROVIDE(SVCall = DefaultExceptionHandler); 77 | PROVIDE(PendSV = DefaultExceptionHandler); 78 | PROVIDE(SysTick = DefaultExceptionHandler); 79 | 80 | -------------------------------------------------------------------------------- /rt/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(custom_test_frameworks)] 2 | #![test_runner(crate::test_runner)] 3 | #![reexport_test_harness_main = "test_main"] 4 | #![no_std] 5 | #![feature(asm)] 6 | #![feature(naked_functions)] 7 | 8 | use core::panic::PanicInfo; 9 | use core::ptr; 10 | use cortex_m_semihosting::debug; 11 | use log::dhprintln; 12 | 13 | #[no_mangle] 14 | pub unsafe extern "C" fn Reset() -> ! { 15 | extern "C" { 16 | static mut _sbss: u8; 17 | static mut _ebss: u8; 18 | static mut _sdata: u8; 19 | static mut _edata: u8; 20 | static _sidata: u8; 21 | static mut _svector_table: u8; 22 | static mut _evector_table: u8; 23 | static _sivector_table: u8; 24 | static mut _sirq_table: u8; 25 | static mut _eirq_table: u8; 26 | } 27 | 28 | let count = &_evector_table as *const u8 as usize - &_svector_table as *const u8 as usize; 29 | ptr::copy_nonoverlapping( 30 | &_sivector_table as *const u8, 31 | &mut _svector_table as *mut u8, 32 | count, 33 | ); 34 | let count = &_eirq_table as *const u8 as usize - &_sirq_table as *const u8 as usize; 35 | ptr::write_bytes(&mut _sirq_table as *mut u8, 0, count); 36 | // write to VTOR 37 | ptr::write_volatile(0xE000_ED08 as *mut u32, &_svector_table as *const u8 as u32); 38 | 39 | let count = &_ebss as *const u8 as usize - &_sbss as *const u8 as usize; 40 | ptr::write_bytes(&mut _sbss as *mut u8, 0, count); 41 | 42 | let count = &_edata as *const u8 as usize - &_sdata as *const u8 as usize; 43 | ptr::copy_nonoverlapping(&_sidata as *const u8, &mut _sdata as *mut u8, count); 44 | 45 | extern "Rust" { 46 | fn main() -> !; 47 | } 48 | 49 | main() 50 | } 51 | 52 | #[link_section = ".vector_table.reset_vector"] 53 | #[no_mangle] 54 | pub static RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; 55 | 56 | #[panic_handler] 57 | fn panic(_panic: &PanicInfo<'_>) -> ! { 58 | loop {} 59 | } 60 | 61 | #[macro_export] 62 | macro_rules! entry { 63 | ($path:path) => { 64 | #[cfg(not(test))] 65 | #[export_name = "main"] 66 | pub unsafe fn __main() -> ! { 67 | let f: fn() -> ! = $path; 68 | 69 | f() 70 | } 71 | #[cfg(test)] 72 | #[export_name = "main"] 73 | pub unsafe fn __main() -> ! { 74 | test_main(); 75 | loop {} 76 | } 77 | }; 78 | } 79 | 80 | #[repr(C)] 81 | #[derive(Clone, Copy)] 82 | pub union Vector { 83 | pub reserved: u32, 84 | pub handler: unsafe extern "C" fn(), 85 | } 86 | 87 | extern "C" { 88 | fn NMI(); 89 | fn HardFault(); 90 | fn MemManage(); 91 | fn BusFault(); 92 | fn UsageFault(); 93 | fn PendSV(); 94 | fn SysTick(); 95 | } 96 | 97 | #[link_section = ".vector_table.exceptions"] 98 | #[no_mangle] 99 | pub static EXCEPTIONS: [Vector; 14] = [ 100 | Vector { handler: NMI }, 101 | Vector { handler: HardFault }, 102 | Vector { handler: MemManage }, 103 | Vector { handler: BusFault }, 104 | Vector { 105 | handler: UsageFault, 106 | }, 107 | Vector { reserved: 0 }, 108 | Vector { reserved: 0 }, 109 | Vector { reserved: 0 }, 110 | Vector { reserved: 0 }, 111 | Vector { handler: SVCall }, 112 | Vector { reserved: 0 }, 113 | Vector { reserved: 0 }, 114 | Vector { handler: PendSV }, 115 | Vector { handler: SysTick }, 116 | ]; 117 | 118 | #[cfg(not(debug_assertions))] 119 | #[no_mangle] 120 | pub extern "C" fn DefaultExceptionHandler() { 121 | loop {} 122 | } 123 | 124 | #[cfg(debug_assertions)] 125 | #[no_mangle] 126 | pub extern "C" fn DefaultExceptionHandler() { 127 | debug::exit(debug::EXIT_SUCCESS); 128 | loop {} 129 | } 130 | 131 | #[no_mangle] 132 | #[used] 133 | pub static mut SYSCALL_FIRED: usize = 0; 134 | 135 | #[no_mangle] 136 | #[naked] 137 | pub unsafe extern "C" fn SVCall() { 138 | asm!( 139 | "cmp lr, #0xfffffff9", 140 | "bne 1f", 141 | /* switch thread mode to unprivileged */ 142 | "movw lr, #0xfffd", 143 | "movt lr, #0xffff", 144 | "bx lr", 145 | "1:", 146 | "ldr r0, =SYSCALL_FIRED", 147 | "mov r1, #1", 148 | "str r1, [r0, #0]", 149 | 150 | "movw lr, #0xfff9", 151 | "movt lr, #0xffff", 152 | "bx lr", 153 | options(noreturn), 154 | ); 155 | } 156 | 157 | pub fn test_runner(tests: &[&dyn Fn()]) { 158 | dhprintln!("Running {} tests", tests.len()); 159 | for test in tests { 160 | test(); 161 | } 162 | debug::exit(debug::EXIT_SUCCESS); 163 | } 164 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2021-10-05 2 | -------------------------------------------------------------------------------- /user/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "user" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | kernel = { path = "../kernel" } 9 | -------------------------------------------------------------------------------- /user/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(asm)] 3 | 4 | pub mod syscall; 5 | pub mod util; 6 | -------------------------------------------------------------------------------- /user/src/syscall.rs: -------------------------------------------------------------------------------- 1 | use kernel::syscall_id::*; 2 | 3 | pub fn dormant() { 4 | unsafe { 5 | asm!( 6 | "svc 1", 7 | in("r0") DORMANT, 8 | ); 9 | } 10 | } 11 | 12 | pub fn send_message(id: u32, message: u32) -> bool { 13 | let result: usize; 14 | unsafe { 15 | asm!( 16 | "svc 1", 17 | lateout("r0") result, 18 | in("r0") SEND_MESSAGE, 19 | in("r1") id, 20 | in("r2") message, 21 | ); 22 | } 23 | result > 0 24 | } 25 | 26 | pub fn receive_message() -> Option { 27 | let result: usize; 28 | let message: u32; 29 | unsafe { 30 | asm!( 31 | "svc 1", 32 | lateout("r0")result, 33 | out("r1") message, 34 | in("r0") RECEIVE_MESSAGE, 35 | ); 36 | } 37 | 38 | if result > 0 { 39 | Some(message) 40 | } else { 41 | None 42 | } 43 | } 44 | 45 | pub fn wait_for_interrupt(id: u32) { 46 | unsafe { 47 | asm!( 48 | "svc 1", 49 | in("r0") WAIT_IRQ, 50 | in("r1") id, 51 | ); 52 | } 53 | } 54 | 55 | pub fn wait_for_event() { 56 | unsafe { 57 | asm!( 58 | "svc 1", 59 | in("r0") YIELD, 60 | ); 61 | } 62 | } 63 | 64 | pub fn wait_for_systick() { 65 | unsafe { 66 | asm!( 67 | "svc 1", 68 | in("r0") WAIT_SYSTICK, 69 | ); 70 | } 71 | } 72 | 73 | pub fn print_str(message: &str) { 74 | let message_ptr = message.as_ptr(); 75 | let length = message.bytes().len(); 76 | unsafe { 77 | asm!( 78 | "svc 1", 79 | in("r0") 1, 80 | in("r1") message_ptr, 81 | in("r2") length, 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /user/src/util.rs: -------------------------------------------------------------------------------- 1 | pub fn get_sp() -> u32 { 2 | let result; 3 | unsafe { 4 | asm!( 5 | "mov sp, r0", 6 | out("r0") result, 7 | 8 | ); 9 | } 10 | result 11 | } 12 | -------------------------------------------------------------------------------- /util/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /util/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "util" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | [dev-dependencies] 8 | rand = "0.3" 9 | 10 | [dependencies] 11 | array-init = "2.0" 12 | lock_api = { version = "0.4", features = ["nightly"] } 13 | 14 | [features] 15 | alloc = [] 16 | 17 | -------------------------------------------------------------------------------- /util/src/allocator.rs: -------------------------------------------------------------------------------- 1 | use core::ptr::NonNull; 2 | 3 | use alloc::alloc::{GlobalAlloc, Layout}; 4 | use crate::sync::UnsafeLock; 5 | 6 | const LIST_LEN: usize = 5; 7 | 8 | struct FreeArea { 9 | next: Option>, 10 | _marker: core::marker::PhantomPinned, 11 | } 12 | 13 | impl FreeArea { 14 | const fn new() -> Self { 15 | Self { 16 | next: None, 17 | _marker: core::marker::PhantomPinned, 18 | } 19 | } 20 | 21 | fn as_mut(&mut self) -> *mut Self { 22 | self as *mut _ 23 | } 24 | } 25 | 26 | unsafe impl Send for FreeArea {} 27 | 28 | 29 | struct Allocator { 30 | free_list_head: [FreeArea; LIST_LEN], 31 | } 32 | 33 | const MIN_BASE_SIZE: usize = core::mem::size_of::(); 34 | const MAX_BASE_SIZE: usize = MIN_BASE_SIZE << (LIST_LEN - 1); 35 | 36 | impl Allocator { 37 | pub const fn new() -> Self { 38 | Self { 39 | free_list_head: [FreeArea::new(), FreeArea::new(), FreeArea::new(), FreeArea::new(), FreeArea::new()], 40 | } 41 | } 42 | 43 | pub fn init(&mut self, heap_start: usize, heap_end: usize) { 44 | self.add_area(heap_start, heap_end); 45 | } 46 | 47 | fn optimize_area(&mut self, idx: usize) { 48 | let size = MIN_BASE_SIZE << idx; 49 | if self.free_list_head[idx].next.is_some() { 50 | let mut prev_ptr = self.free_list_head[idx].as_mut(); 51 | let mut tar = unsafe { &mut *(self.free_list_head[idx].next.as_ref().unwrap().as_ptr() as *mut FreeArea) }; 52 | while tar.next.is_some() { 53 | let tar_ptr = tar.as_mut(); 54 | let next_ptr = tar.next.as_ref().unwrap().as_ptr() as *mut FreeArea; 55 | if tar_ptr as usize + size == next_ptr as usize { 56 | unsafe { 57 | (*prev_ptr).next = (*next_ptr).next; 58 | } 59 | self.push_area_to_list(idx+1, tar_ptr as usize); 60 | break; 61 | } 62 | prev_ptr = tar_ptr; 63 | tar = unsafe { &mut *(next_ptr as *mut FreeArea) }; 64 | } 65 | } 66 | } 67 | 68 | fn push_area_to_list(&mut self, idx: usize, addr: usize) { 69 | let mut prev = self.free_list_head[idx].as_mut(); 70 | let mut next = self.free_list_head[idx].next; 71 | while next.is_some() { 72 | let next_ptr = next.as_ref().unwrap().as_ptr(); 73 | if next_ptr as usize > addr { 74 | break; 75 | } 76 | prev = unsafe { &mut *(next_ptr as *mut FreeArea) }; 77 | next = unsafe { (&*(next_ptr as *mut FreeArea)).next }; 78 | } 79 | let new_area = unsafe { &mut *(addr as *mut FreeArea) }; 80 | unsafe { 81 | (*prev).next = Some(NonNull::new_unchecked(new_area as *mut _ as *mut u8)); 82 | } 83 | new_area.next = next; 84 | 85 | // join consecutive areas 86 | if idx < LIST_LEN - 1 { 87 | self.optimize_area(idx); 88 | } 89 | } 90 | 91 | pub fn add_area(&mut self, heap_start: usize, heap_end: usize) { 92 | let heap_start = (heap_start + MIN_BASE_SIZE - 1) / MIN_BASE_SIZE * MIN_BASE_SIZE; 93 | let mut current = heap_start; 94 | let mut idx = 0; 95 | 96 | 97 | // align to max base size 98 | while current + (MIN_BASE_SIZE << idx) <= heap_end && idx < LIST_LEN - 1 { 99 | let base_size = MIN_BASE_SIZE << idx; 100 | let next_base_size = base_size * 2; 101 | if current % next_base_size > 0 { 102 | self.push_area_to_list(idx, current); 103 | current += base_size; 104 | } 105 | idx += 1; 106 | } 107 | while current + MAX_BASE_SIZE <= heap_end && idx < LIST_LEN { 108 | self.push_area_to_list(idx, current); 109 | current += MAX_BASE_SIZE; 110 | } 111 | // allocate rest of area 112 | idx += 1; 113 | while current < heap_end && idx > 0 { 114 | idx -= 1; 115 | let base_size = MIN_BASE_SIZE << idx; 116 | if ((heap_end - current) & base_size) > 0 { 117 | self.push_area_to_list(idx, current); 118 | current += base_size; 119 | } 120 | } 121 | } 122 | 123 | fn alloc(&mut self, layout: Layout) -> *mut u8 { 124 | let size = layout.size(); 125 | let align = layout.align(); 126 | let mut idx = 0; 127 | while (MIN_BASE_SIZE << idx) < size && idx < LIST_LEN { 128 | idx += 1; 129 | } 130 | 131 | let min_idx = idx; 132 | while idx < LIST_LEN { 133 | let target_list = &mut self.free_list_head[idx]; 134 | let mut flag = false; 135 | let mut prev = target_list as *mut _ as *mut u8; 136 | let mut next = target_list.next; 137 | while next.is_some() { 138 | let next_ptr = next.as_ref().unwrap().as_ptr(); 139 | if (next_ptr as usize) % align + size <= (MIN_BASE_SIZE << idx) { 140 | flag = true; 141 | break; 142 | } 143 | prev = next_ptr; 144 | next = unsafe { &*(prev as *mut FreeArea) }.next; 145 | } 146 | if flag { 147 | let next_ptr = next.as_ref().unwrap().as_ptr(); 148 | unsafe { 149 | (*(prev as *mut FreeArea)).next = (*(next_ptr as *mut FreeArea)).next.take(); 150 | } 151 | let next_addr = next_ptr as usize; 152 | let tar_addr = (next_addr + align - 1) / align * align; 153 | let tar_end = tar_addr + (MIN_BASE_SIZE << min_idx); 154 | let next_end = next_addr + (MIN_BASE_SIZE << idx); 155 | if tar_addr > next_addr { 156 | self.add_area(next_addr, tar_addr); 157 | } 158 | if next_end > tar_end { 159 | self.add_area(tar_end, next_end); 160 | } 161 | return next_ptr; 162 | } 163 | 164 | 165 | idx += 1; 166 | } 167 | 168 | core::ptr::null_mut() 169 | } 170 | 171 | fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { 172 | let heap_start = ptr as usize; 173 | let heap_end = heap_start + (layout.size() + MIN_BASE_SIZE - 1) / MIN_BASE_SIZE * MIN_BASE_SIZE; 174 | self.add_area(heap_start, heap_end); 175 | } 176 | } 177 | 178 | pub struct LockedAllocator(UnsafeLock); 179 | 180 | impl LockedAllocator { 181 | pub const fn new() -> Self { 182 | Self(UnsafeLock::new(Allocator::new())) 183 | } 184 | 185 | pub fn add_area(&self, heap_start: usize, heap_end: usize) { 186 | self.0.lock().add_area(heap_start, heap_end); 187 | } 188 | } 189 | 190 | unsafe impl GlobalAlloc for LockedAllocator { 191 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 192 | let mut lock = self.0.lock(); 193 | lock.alloc(layout) 194 | } 195 | 196 | unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 197 | let mut lock = self.0.lock(); 198 | lock.dealloc(ptr, layout); 199 | } 200 | } 201 | 202 | #[cfg(test)] 203 | mod tests { 204 | use super::*; 205 | use alloc::vec; 206 | use array_init::array_init; 207 | use rand::{Rng, SeedableRng, StdRng}; 208 | extern crate std; 209 | 210 | #[repr(align(16))] 211 | pub struct AlignedStruct(u32); 212 | 213 | 214 | #[test] 215 | fn test_small() { 216 | let b = [0u8; 1024]; 217 | let heap_start = &b[0] as *const u8 as usize; 218 | let heap_end = heap_start + 1024; 219 | let mut allocator = Allocator::new(); 220 | 221 | allocator.add_area(heap_start, heap_end); 222 | 223 | let mem1 = allocator.alloc(Layout::new::()); 224 | let mem2 = allocator.alloc(Layout::new::()); 225 | let mem3 = allocator.alloc(Layout::new::()); 226 | let mem4 = allocator.alloc(Layout::new::()); 227 | 228 | assert_ne!(mem1, mem2); 229 | assert_ne!(mem2, mem3); 230 | assert_ne!(mem3, mem2); 231 | assert!(mem4 as usize % 16 == 0); 232 | 233 | let val1: &mut u64 = unsafe { &mut *(mem1 as usize as *mut u64) }; 234 | let val2: &mut u128 = unsafe { &mut *(mem2 as usize as *mut u128) }; 235 | let val3: &mut u32 = unsafe { &mut *(mem3 as usize as *mut u32) }; 236 | let val4: &mut AlignedStruct = unsafe { &mut *(mem4 as usize as *mut AlignedStruct) }; 237 | *val1 = (1 << 62) - 1; 238 | *val2 = (1 << 126) - 1; 239 | *val3 = (1 << 30) -1; 240 | val4.0 = (1 << 30) - 2; 241 | 242 | allocator.dealloc(mem2, Layout::new::()); 243 | let mem5 = allocator.alloc(Layout::new::()); 244 | let val5: &mut u32 = unsafe { &mut *(mem5 as usize as *mut u32) }; 245 | *val5 = 1; 246 | 247 | assert_eq!((1 << 62) - 1, *val1); 248 | assert_eq!((1 << 30) - 1, *val3); 249 | assert_eq!((1 << 30) - 2, val4.0); 250 | assert_eq!(1, *val5); 251 | } 252 | 253 | #[test] 254 | fn test_rand() { 255 | let seed: &[_] = &[1, 2, 3, 4]; 256 | let mut rng: StdRng = SeedableRng::from_seed(seed); 257 | let mut items: [usize; 128] = array_init(|i| i); 258 | rng.shuffle(&mut items); 259 | 260 | let buffer = [0u8; 1031]; 261 | let heap_start = &buffer[0] as *const u8 as usize; 262 | let heap_end = heap_start + 1031; 263 | let mut allocator = Allocator::new(); 264 | 265 | allocator.add_area(heap_start, heap_end); 266 | let mut ptrs = vec![core::ptr::null_mut(); 128]; 267 | for i in 0..128 { 268 | ptrs[i] = allocator.alloc(Layout::new::()); 269 | unsafe { 270 | *(ptrs[i] as usize as *mut i64) = i as i64; 271 | } 272 | } 273 | for i in 0..64 { 274 | let tar = items[i]; 275 | allocator.dealloc(ptrs[tar], Layout::new::()); 276 | } 277 | for i in 64..128 { 278 | let tar = items[i]; 279 | assert_eq!(tar as i64, unsafe { *(ptrs[tar] as usize as *mut i64) }); 280 | } 281 | for i in 0..64 { 282 | let tar = items[i]; 283 | ptrs[tar] = allocator.alloc(Layout::new::()); 284 | unsafe { 285 | *(ptrs[tar] as usize as *mut i64) = -(tar as i64); 286 | } 287 | } 288 | for i in 0..128 { 289 | let tar = items[i]; 290 | if i < 64 { 291 | assert_eq!(-(tar as i64), unsafe { *(ptrs[tar] as usize as *mut i64) }); 292 | } else { 293 | assert_eq!(tar as i64, unsafe { *(ptrs[tar] as usize as *mut i64) }); 294 | } 295 | } 296 | } 297 | 298 | #[test] 299 | fn test_rand_aligned() { 300 | let seed: &[_] = &[1, 2, 3, 5]; 301 | let mut rng: StdRng = SeedableRng::from_seed(seed); 302 | let mut items: [usize; 128] = array_init(|i| i); 303 | rng.shuffle(&mut items); 304 | 305 | let buffer = [0u8; 2055]; 306 | let heap_start = &buffer[0] as *const u8 as usize; 307 | let heap_end = heap_start + 2055; 308 | let mut allocator = Allocator::new(); 309 | 310 | allocator.add_area(heap_start, heap_end); 311 | let mut ptrs = vec![core::ptr::null_mut(); 128]; 312 | for i in 0..128 { 313 | ptrs[i] = allocator.alloc(Layout::new::()); 314 | unsafe { 315 | (*(ptrs[i] as usize as *mut AlignedStruct)).0 = i as u32; 316 | } 317 | assert!(ptrs[i] as usize % 16 == 0); 318 | } 319 | for i in 0..64 { 320 | let tar = items[i]; 321 | allocator.dealloc(ptrs[tar], Layout::new::()); 322 | } 323 | for i in 64..128 { 324 | let tar = items[i]; 325 | assert_eq!(tar as u32, unsafe { (*(ptrs[tar] as usize as *mut AlignedStruct)).0 }); 326 | assert!(ptrs[tar] as usize % 16 == 0); 327 | } 328 | for i in 0..64 { 329 | let tar = items[i]; 330 | ptrs[tar] = allocator.alloc(Layout::new::()); 331 | unsafe { 332 | (*(ptrs[tar] as usize as *mut AlignedStruct)).0 = tar as u32 + 256; 333 | } 334 | } 335 | for i in 0..128 { 336 | let tar = items[i]; 337 | if i < 64 { 338 | assert_eq!(tar as u32 + 256, unsafe { (*(ptrs[tar] as usize as *mut AlignedStruct)).0 }); 339 | } else { 340 | assert_eq!(tar as u32, unsafe { (*(ptrs[tar] as usize as *mut AlignedStruct)).0 }); 341 | } 342 | } 343 | } 344 | 345 | } 346 | -------------------------------------------------------------------------------- /util/src/avl_tree.rs: -------------------------------------------------------------------------------- 1 | use crate::binary_tree::BinaryTree; 2 | use core::cmp; 3 | use core::mem; 4 | use core::ops::{Deref, DerefMut}; 5 | use core::ptr::NonNull; 6 | 7 | pub struct Node<'a, K, V> { 8 | pub item: (K, V), 9 | parent: Option>>, 10 | left: Option<&'a mut Node<'a, K, V>>, 11 | right: Option<&'a mut Node<'a, K, V>>, 12 | 13 | height: usize, 14 | } 15 | 16 | impl<'a, K, V> Node<'a, K, V> { 17 | pub fn new(key: K, value: V) -> Node<'a, K, V> { 18 | Node { 19 | item: (key, value), 20 | parent: None, 21 | left: None, 22 | right: None, 23 | height: 1, 24 | } 25 | } 26 | 27 | fn is_same(&self, node: &Node<'a, K, V>) -> bool { 28 | (self as *const Node<'a, K, V>) == (node as *const Node<'a, K, V>) 29 | } 30 | 31 | fn get_parent_ref(&self) -> Option<&Node<'a, K, V>> { 32 | self.parent.as_ref().map(|ptr| unsafe { ptr.as_ref() }) 33 | } 34 | 35 | fn get_parent_mut(&mut self) -> Option<&mut Node<'a, K, V>> { 36 | self.parent.as_mut().map(|ptr| unsafe { ptr.as_mut() }) 37 | } 38 | 39 | fn get_min_child(&self) -> &Node<'a, K, V> { 40 | let mut current = self; 41 | while current.left.is_some() { 42 | current = current.left.as_ref().unwrap(); 43 | } 44 | current 45 | } 46 | 47 | fn get_min_child_mut(&mut self) -> &mut Node<'a, K, V> { 48 | let mut current = self; 49 | while current.left.is_some() { 50 | current = current.left.as_mut().unwrap(); 51 | } 52 | current 53 | } 54 | 55 | fn update_height(&mut self) { 56 | self.height = 1 + cmp::max( 57 | self.left.as_ref().map(|n| n.height).unwrap_or(0), 58 | self.right.as_ref().map(|n| n.height).unwrap_or(0), 59 | ); 60 | self.get_parent_mut().map(|p| p.update_height()); 61 | } 62 | 63 | fn rotate_right(&mut self) -> bool { 64 | if self.left.is_none() { 65 | return false; 66 | } 67 | 68 | let mut left_node = self.left.take(); 69 | let left_node_ref = left_node.as_mut().unwrap(); 70 | 71 | mem::swap(self, left_node_ref); 72 | self.parent = None; 73 | let self_ptr = unsafe { NonNull::new_unchecked(self as *mut Node<'a, K, V>) }; 74 | left_node_ref.parent = Some(self_ptr); 75 | let left_right_node = self.right.take(); 76 | left_node_ref.left = left_right_node; 77 | self.left.as_mut().map(|node| { 78 | node.parent = Some(self_ptr); 79 | }); 80 | let left_node_ptr = 81 | unsafe { NonNull::new_unchecked(*left_node_ref as *mut Node<'a, K, V>) }; 82 | left_node_ref.right.as_mut().map(|node| { 83 | node.parent = Some(left_node_ptr); 84 | }); 85 | self.right = left_node; 86 | self.right.as_mut().map(|node| node.update_height()); 87 | true 88 | } 89 | 90 | fn rotate_left(&mut self) -> bool { 91 | if self.right.is_none() { 92 | return false; 93 | } 94 | 95 | let mut right_node = self.right.take(); 96 | let right_node_ref = right_node.as_mut().unwrap(); 97 | 98 | mem::swap(self, right_node_ref); 99 | self.parent = None; 100 | let self_ptr = unsafe { NonNull::new_unchecked(self as *mut Node<'a, K, V>) }; 101 | right_node_ref.parent = Some(self_ptr); 102 | let right_left_node = self.left.take(); 103 | right_node_ref.right = right_left_node; 104 | self.right.as_mut().map(|node| { 105 | node.parent = Some(self_ptr); 106 | }); 107 | let right_node_ptr = 108 | unsafe { NonNull::new_unchecked(*right_node_ref as *mut Node<'a, K, V>) }; 109 | right_node_ref.left.as_mut().map(|node| { 110 | node.parent = Some(right_node_ptr); 111 | }); 112 | self.left = right_node; 113 | self.left.as_mut().map(|node| node.update_height()); 114 | true 115 | } 116 | } 117 | 118 | pub struct AvlTree<'a, K, V> { 119 | head: Option<&'a mut Node<'a, K, V>>, 120 | size: usize, 121 | } 122 | 123 | pub struct Iter<'a, K, V> { 124 | current: Option<*const Node<'a, K, V>>, 125 | size: usize, 126 | } 127 | 128 | pub struct IterMut<'a, K, V> { 129 | current: Option>>, 130 | size: usize, 131 | } 132 | 133 | #[derive(Debug, PartialEq)] 134 | enum BalanceResult { 135 | Balanced, 136 | LeftHeavy, 137 | RightHeavy, 138 | } 139 | 140 | // TODO: implement rotate 141 | impl<'a, K, V> AvlTree<'a, K, V> 142 | where 143 | K: Ord, 144 | { 145 | pub fn new() -> AvlTree<'a, K, V> { 146 | AvlTree { 147 | head: None, 148 | size: 0, 149 | } 150 | } 151 | 152 | pub fn iter(&self) -> Iter<'a, K, V> { 153 | if self.head.is_none() { 154 | Iter { 155 | current: None, 156 | size: 0, 157 | } 158 | } else { 159 | let min_child = self.head.as_ref().unwrap().get_min_child(); 160 | Iter { 161 | current: Some(min_child), 162 | size: self.size, 163 | } 164 | } 165 | } 166 | 167 | pub fn iter_mut(&mut self) -> IterMut<'a, K, V> { 168 | if self.head.is_none() { 169 | IterMut { 170 | current: None, 171 | size: 0, 172 | } 173 | } else { 174 | let min_child = self.head.as_mut().unwrap().get_min_child_mut(); 175 | IterMut { 176 | current: Some(unsafe { NonNull::new_unchecked(min_child as *mut Node) }), 177 | size: self.size, 178 | } 179 | } 180 | } 181 | 182 | fn check_balanced(&self) -> BalanceResult { 183 | if self.head.is_none() { 184 | return BalanceResult::Balanced; 185 | } 186 | let head = self.head.as_ref().unwrap(); 187 | let left_height = head.left.as_ref().map(|n| n.height).unwrap_or(0); 188 | let right_height = head.right.as_ref().map(|n| n.height).unwrap_or(0); 189 | if left_height >= right_height + 2 { 190 | BalanceResult::LeftHeavy 191 | } else if left_height + 2 <= right_height { 192 | BalanceResult::RightHeavy 193 | } else { 194 | BalanceResult::Balanced 195 | } 196 | } 197 | 198 | fn balance(&mut self) { 199 | match self.check_balanced() { 200 | BalanceResult::LeftHeavy => { 201 | let head = self.head.as_mut().unwrap(); 202 | let left = head.left.as_mut().unwrap(); 203 | let llh = left.left.as_ref().map(|n| n.height).unwrap_or(0); 204 | let lrh = left.right.as_ref().map(|n| n.height).unwrap_or(0); 205 | if llh < lrh { 206 | left.rotate_left(); 207 | } 208 | head.rotate_right(); 209 | } 210 | BalanceResult::RightHeavy => { 211 | let head = self.head.as_mut().unwrap(); 212 | let right = head.right.as_mut().unwrap(); 213 | let rlh = right.left.as_ref().map(|n| n.height).unwrap_or(0); 214 | let rrh = right.right.as_ref().map(|n| n.height).unwrap_or(0); 215 | if rrh < rlh { 216 | right.rotate_right(); 217 | } 218 | head.rotate_left(); 219 | } 220 | _ => {} 221 | } 222 | } 223 | } 224 | 225 | impl<'a, K, V> BinaryTree<'a, K, V, Node<'a, K, V>> for AvlTree<'a, K, V> 226 | where 227 | K: Ord, 228 | { 229 | fn get(&self, key: &K) -> Option<&V> { 230 | if self.head.is_none() { 231 | None 232 | } else { 233 | let mut current = self.head.as_ref().unwrap(); 234 | while current.item.0 != *key { 235 | if current.item.0 < *key { 236 | if current.right.is_none() { 237 | return None; 238 | } else { 239 | current = current.right.as_ref().unwrap(); 240 | } 241 | } else { 242 | if current.left.is_none() { 243 | return None; 244 | } else { 245 | current = current.left.as_ref().unwrap(); 246 | } 247 | } 248 | } 249 | Some(&(current.item.1)) 250 | } 251 | } 252 | 253 | fn borrow(&self, key: &K) -> Option<&'a V> { 254 | let mut result = None; 255 | self.head.as_ref().map(|head| unsafe { 256 | let mut current = (*head as *const Node<'a, K, V>).clone(); 257 | while (*current).item.0 != *key { 258 | if (*current).item.0 < *key { 259 | if (*current).right.is_none() { 260 | return; 261 | } else { 262 | current = (*(*current).right.as_ref().unwrap()) as *const Node<'a, K, V>; 263 | } 264 | } else { 265 | if (*current).left.is_none() { 266 | return; 267 | } else { 268 | current = (*(*current).left.as_ref().unwrap()) as *const Node<'a, K, V>; 269 | } 270 | } 271 | } 272 | result = Some(&(*current).item.1); 273 | }); 274 | result 275 | } 276 | 277 | fn get_mut(&mut self, key: &K) -> Option<&mut V> { 278 | if self.head.is_none() { 279 | None 280 | } else { 281 | let mut current = self.head.as_mut().unwrap(); 282 | while current.item.0 != *key { 283 | if current.item.0 < *key { 284 | if current.right.is_none() { 285 | return None; 286 | } else { 287 | current = current.right.as_mut().unwrap(); 288 | } 289 | } else { 290 | if current.left.is_none() { 291 | return None; 292 | } else { 293 | current = current.left.as_mut().unwrap(); 294 | } 295 | } 296 | } 297 | Some(&mut (current.item.1)) 298 | } 299 | } 300 | 301 | fn borrow_mut(&mut self, key: &K) -> Option<&'a mut V> { 302 | let mut result = None; 303 | self.head.as_mut().map(|head| unsafe { 304 | let mut current = *head as *mut Node<'a, K, V>; 305 | while (*current).item.0 != *key { 306 | if (*current).item.0 < *key { 307 | if (*current).right.is_none() { 308 | return; 309 | } else { 310 | current = (*(*current).right.as_mut().unwrap()) as *mut Node<'a, K, V>; 311 | } 312 | } else { 313 | if (*current).left.is_none() { 314 | return; 315 | } else { 316 | current = (*(*current).left.as_mut().unwrap()) as *mut Node<'a, K, V>; 317 | } 318 | } 319 | } 320 | result = Some(&mut (*current).item.1); 321 | }); 322 | result 323 | } 324 | 325 | fn insert(&mut self, node: &'a mut Node<'a, K, V>) { 326 | if self.head.is_none() { 327 | self.head.replace(node); 328 | } else { 329 | let mut current = self.head.as_mut().unwrap(); 330 | loop { 331 | if current.item.0 < node.item.0 { 332 | if current.right.is_none() { 333 | let np = unsafe { NonNull::new_unchecked(*current as *mut Node<'a, K, V>) }; 334 | node.parent.replace(np); 335 | current.right.replace(node); 336 | current.update_height(); 337 | break; 338 | } else { 339 | current = current.right.as_mut().unwrap(); 340 | } 341 | } else { 342 | if current.left.is_none() { 343 | let np = unsafe { NonNull::new_unchecked(*current as *mut Node<'a, K, V>) }; 344 | node.parent.replace(np); 345 | current.left.replace(node); 346 | current.update_height(); 347 | break; 348 | } else { 349 | current = current.left.as_mut().unwrap(); 350 | } 351 | } 352 | } 353 | } 354 | self.balance(); 355 | self.size += 1; 356 | } 357 | } 358 | 359 | impl<'a, K, V> Deref for Node<'a, K, V> { 360 | type Target = (K, V); 361 | 362 | fn deref(&self) -> &Self::Target { 363 | &self.item 364 | } 365 | } 366 | 367 | impl<'a, K, V> DerefMut for Node<'a, K, V> { 368 | fn deref_mut(&mut self) -> &mut Self::Target { 369 | &mut self.item 370 | } 371 | } 372 | 373 | impl<'a, K, V> Iterator for Iter<'a, K, V> { 374 | type Item = &'a (K, V); 375 | 376 | fn next(&mut self) -> Option<&'a (K, V)> { 377 | if self.size == 0 { 378 | None 379 | } else { 380 | let result = unsafe { &(*self.current.unwrap()).item }; 381 | self.current = self 382 | .current 383 | .map(|item| unsafe { 384 | let node = &(*item); 385 | self.size -= 1; 386 | match &node.right { 387 | None => { 388 | let mut parent = node.get_parent_ref(); 389 | let mut child = node; 390 | while parent.is_some() 391 | && parent.unwrap().right.is_some() 392 | && parent.unwrap().right.as_ref().unwrap().is_same(child) 393 | { 394 | child = &(*parent.unwrap()); 395 | parent = parent.unwrap().get_parent_ref(); 396 | } 397 | parent.map(|par| par as *const Node) 398 | } 399 | Some(right) => Some(right.get_min_child() as *const Node), 400 | } 401 | }) 402 | .unwrap(); 403 | Some(result) 404 | } 405 | } 406 | 407 | fn size_hint(&self) -> (usize, Option) { 408 | (self.size, Some(self.size)) 409 | } 410 | } 411 | 412 | impl<'a, K, V> Iterator for IterMut<'a, K, V> { 413 | type Item = &'a mut (K, V); 414 | 415 | fn next(&mut self) -> Option<&'a mut (K, V)> { 416 | if self.size == 0 { 417 | None 418 | } else { 419 | let result = self.current.unwrap(); 420 | self.current = self 421 | .current 422 | .map(|mut item| unsafe { 423 | let node = item.as_mut(); 424 | self.size -= 1; 425 | match &mut node.right { 426 | None => { 427 | let mut parent = node.parent; 428 | let mut child = NonNull::new_unchecked(node as *mut Node); 429 | while parent.is_some() 430 | && parent.unwrap().as_ref().right.is_some() 431 | && parent 432 | .unwrap() 433 | .as_ref() 434 | .right 435 | .as_ref() 436 | .unwrap() 437 | .is_same(child.as_ref()) 438 | { 439 | child = parent.unwrap(); 440 | parent = parent.unwrap().as_ref().parent; 441 | } 442 | parent 443 | } 444 | Some(right) => Some(NonNull::new_unchecked( 445 | right.get_min_child_mut() as *mut Node 446 | )), 447 | } 448 | }) 449 | .unwrap(); 450 | Some(unsafe { &mut ((*result.as_ptr()).item) }) 451 | } 452 | } 453 | 454 | fn size_hint(&self) -> (usize, Option) { 455 | (self.size, Some(self.size)) 456 | } 457 | } 458 | 459 | #[cfg(test)] 460 | mod tests { 461 | use super::*; 462 | use array_init::array_init; 463 | use rand::{Rng, SeedableRng, StdRng}; 464 | 465 | #[test] 466 | fn test_simple() { 467 | let mut btree = AvlTree::new(); 468 | assert!(btree.get(&0).is_none()); 469 | let mut node1 = Node::new(1, "hello"); 470 | btree.insert(&mut node1); 471 | assert_eq!(btree.get(&1).unwrap(), &"hello"); 472 | let mut node2 = Node::new(2, "world"); 473 | btree.insert(&mut node2); 474 | assert_eq!(&"hello", btree.get(&1).unwrap()); 475 | assert_eq!(&"world", btree.get(&2).unwrap()); 476 | } 477 | 478 | #[test] 479 | fn test_iter() { 480 | let mut btree = AvlTree::new(); 481 | let mut node1 = Node::new(9, "third"); 482 | let mut node2 = Node::new(1, "first"); 483 | let mut node3 = Node::new(3, "second"); 484 | btree.insert(&mut node1); 485 | btree.insert(&mut node2); 486 | btree.insert(&mut node3); 487 | let expected = [(1, "first"), (3, "second"), (9, "third")]; 488 | for (i, (key, value)) in btree.iter().enumerate() { 489 | assert_eq!(&expected[i].0, key); 490 | assert_eq!(&expected[i].1, value); 491 | } 492 | } 493 | 494 | #[test] 495 | fn test_iter_mut() { 496 | let mut btree = AvlTree::new(); 497 | let mut node1 = Node::new(9, "third"); 498 | let mut node2 = Node::new(1, "first"); 499 | let mut node3 = Node::new(3, "second"); 500 | btree.insert(&mut node1); 501 | btree.insert(&mut node2); 502 | btree.insert(&mut node3); 503 | let expected = [(1, "first"), (3, "second"), (9, "third")]; 504 | let next = ["one", "two", "three"]; 505 | for (i, (key, value)) in btree.iter_mut().enumerate() { 506 | assert_eq!(&expected[i].0, key); 507 | assert_eq!(&expected[i].1, value); 508 | *value = next[i]; 509 | } 510 | for (i, (key, value)) in btree.iter().enumerate() { 511 | assert_eq!(&expected[i].0, key); 512 | assert_eq!(&next[i], value); 513 | } 514 | } 515 | 516 | #[test] 517 | fn test_random() { 518 | let seed: &[_] = &[1, 2, 3, 4]; 519 | let mut rng: StdRng = SeedableRng::from_seed(seed); 520 | let mut nodes: [Node; 100] = array_init(|i| Node::new(i, i)); 521 | rng.shuffle(&mut nodes); 522 | let mut btree = AvlTree::new(); 523 | 524 | for node in nodes.iter_mut() { 525 | let i = node.item.0; 526 | btree.insert(node); 527 | assert_eq!( 528 | btree.check_balanced(), 529 | BalanceResult::Balanced, 530 | "not balanced when inserting {}", 531 | i 532 | ); 533 | } 534 | for i in 0..100 { 535 | assert_eq!(i, *(btree.get(&i).unwrap())); 536 | } 537 | for (i, (key, value)) in btree.iter().enumerate() { 538 | assert_eq!(&i, key); 539 | assert_eq!(&i, value); 540 | } 541 | } 542 | } 543 | -------------------------------------------------------------------------------- /util/src/binary_tree.rs: -------------------------------------------------------------------------------- 1 | pub trait BinaryTree<'a, K, V, N> 2 | where 3 | K: Ord, 4 | { 5 | fn get(&self, key: &K) -> Option<&V>; 6 | fn borrow(&self, key: &K) -> Option<&'a V>; 7 | fn get_mut(&mut self, key: &K) -> Option<&mut V>; 8 | fn borrow_mut(&mut self, key: &K) -> Option<&'a mut V>; 9 | fn insert(&mut self, node: &'a mut N); 10 | } 11 | -------------------------------------------------------------------------------- /util/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![crate_type = "rlib"] 3 | #![feature(const_maybe_uninit_assume_init)] 4 | 5 | pub mod avl_tree; 6 | pub mod binary_tree; 7 | pub mod linked_list; 8 | #[cfg(feature = "alloc")] 9 | pub mod allocator; 10 | pub mod sync; 11 | 12 | #[cfg(feature = "alloc")] 13 | extern crate alloc; 14 | 15 | // copied from https://github.com/tock/tock 16 | macro_rules! static_init { 17 | ($T:ty, $e:expr) => { 18 | // Ideally we could use mem::size_of<$T>, uninitialized or zerod here 19 | // instead of having an `Option`, however that is not currently possible 20 | // in Rust, so in some cases we're wasting up to a word. 21 | { 22 | use core::{mem, ptr}; 23 | // Statically allocate a read-write buffer for the value, write our 24 | // initial value into it (without dropping the initial zeros) and 25 | // return a reference to it. 26 | static mut BUF: Option<$T> = None; 27 | let tmp : &'static mut $T = mem::transmute(&mut BUF); 28 | ptr::write(tmp as *mut $T, $e); 29 | tmp 30 | }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /util/src/linked_list.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Deref, DerefMut}; 2 | use core::ptr::NonNull; 3 | 4 | #[repr(C)] 5 | pub struct ListItem<'a, T> { 6 | pub item: T, 7 | next: Option<&'a mut ListItem<'a, T>>, 8 | prev: Option>>, 9 | } 10 | 11 | pub struct LinkedList<'a, T> { 12 | head: Option<&'a mut ListItem<'a, T>>, 13 | last: Option>>, 14 | len: usize, 15 | } 16 | 17 | pub struct Iter<'a, T> { 18 | head: Option<*const ListItem<'a, T>>, 19 | len: usize, 20 | } 21 | 22 | pub struct IterMut<'a, T> { 23 | head: Option>>, 24 | len: usize, 25 | } 26 | 27 | impl<'a, T> Deref for ListItem<'a, T> { 28 | type Target = T; 29 | 30 | fn deref(&self) -> &Self::Target { 31 | &self.item 32 | } 33 | } 34 | 35 | impl<'a, T> DerefMut for ListItem<'a, T> { 36 | fn deref_mut(&mut self) -> &mut Self::Target { 37 | &mut self.item 38 | } 39 | } 40 | 41 | impl<'a, T> LinkedList<'a, T> { 42 | pub fn new() -> LinkedList<'a, T> { 43 | LinkedList { 44 | head: None, 45 | last: None, 46 | len: 0, 47 | } 48 | } 49 | 50 | pub fn is_empty(&self) -> bool { 51 | self.head.is_none() 52 | } 53 | 54 | pub fn pop(&mut self) -> Option<&'a mut ListItem<'a, T>> { 55 | let next = match self.head.iter_mut().next() { 56 | Some(item) => { 57 | let mut result = (*item).next.take(); 58 | match result.iter_mut().next() { 59 | Some(item) => { 60 | (*item).prev = None; 61 | } 62 | None => {} 63 | } 64 | result 65 | } 66 | None => { 67 | panic!("empty list"); 68 | } 69 | }; 70 | let result = self.head.take(); 71 | if next.is_none() { 72 | self.last = None; 73 | } 74 | self.head = next; 75 | self.len -= 1; 76 | result 77 | } 78 | 79 | pub fn push(&mut self, item: &'a mut ListItem<'a, T>) { 80 | if self.last.is_none() { 81 | let item_ptr = unsafe { NonNull::new_unchecked(item as *mut ListItem) }; 82 | item.prev = None; 83 | item.next = None; 84 | self.last.replace(item_ptr); 85 | self.head.replace(item); 86 | } else { 87 | let mut last_ptr = self.last.unwrap(); 88 | let item_ptr = unsafe { NonNull::new_unchecked(item as *mut ListItem) }; 89 | self.last.replace(item_ptr); 90 | item.prev.replace(last_ptr); 91 | unsafe { 92 | last_ptr.as_mut().next.replace(item); 93 | } 94 | } 95 | self.len += 1; 96 | } 97 | 98 | pub fn head_mut(&mut self) -> Option<&mut &'a mut ListItem<'a, T>> { 99 | self.head.as_mut() 100 | } 101 | 102 | pub fn join(&mut self, target: &mut LinkedList<'a, T>) { 103 | if self.is_empty() { 104 | self.head = target.head.take(); 105 | self.last = target.last.take(); 106 | } else { 107 | let mut tar_head = target.head.take(); 108 | if tar_head.is_some() { 109 | let tar_head_item = tar_head.iter_mut().next().unwrap(); 110 | let mut last_ptr = self.last.unwrap(); 111 | tar_head_item.prev.replace(last_ptr); 112 | unsafe { 113 | last_ptr.as_mut().next = tar_head; 114 | } 115 | self.last = target.last.take(); 116 | } 117 | } 118 | self.len += target.len; 119 | target.len = 0; 120 | } 121 | 122 | pub fn iter(&self) -> Iter<'a, T> { 123 | Iter { 124 | head: self.head.as_ref().map(|item| *item as *const ListItem), 125 | len: self.len, 126 | } 127 | } 128 | 129 | pub fn iter_mut(&mut self) -> IterMut<'a, T> { 130 | IterMut { 131 | head: self 132 | .head 133 | .as_mut() 134 | .map(|item| unsafe { NonNull::new_unchecked(*item as *mut ListItem) }), 135 | len: self.len, 136 | } 137 | } 138 | } 139 | 140 | impl<'a, T> Iterator for Iter<'a, T> { 141 | type Item = &'a T; 142 | 143 | fn next(&mut self) -> Option<&'a T> { 144 | if self.len == 0 { 145 | None 146 | } else { 147 | self.head.map(|item| unsafe { 148 | let node = &(*item); 149 | self.len -= 1; 150 | self.head = node.next.as_ref().map(|item| *item as *const ListItem); 151 | &node.item 152 | }) 153 | } 154 | } 155 | 156 | fn size_hint(&self) -> (usize, Option) { 157 | (self.len, Some(self.len)) 158 | } 159 | } 160 | 161 | impl<'a, T> Iterator for IterMut<'a, T> { 162 | type Item = &'a mut T; 163 | 164 | fn next(&mut self) -> Option<&'a mut T> { 165 | if self.len == 0 { 166 | None 167 | } else { 168 | self.head.map(|ptr| unsafe { 169 | let node = &mut *ptr.as_ptr(); 170 | self.len -= 1; 171 | self.head = node 172 | .next 173 | .as_mut() 174 | .map(|item| NonNull::new_unchecked(*item as *mut ListItem)); 175 | &mut node.item 176 | }) 177 | } 178 | } 179 | 180 | fn size_hint(&self) -> (usize, Option) { 181 | (self.len, Some(self.len)) 182 | } 183 | } 184 | 185 | impl<'a, T> ListItem<'a, T> { 186 | pub fn create(item: T) -> ListItem<'a, T> { 187 | ListItem { 188 | item, 189 | next: None, 190 | prev: None, 191 | } 192 | } 193 | } 194 | 195 | #[cfg(test)] 196 | mod tests { 197 | use super::*; 198 | 199 | #[test] 200 | fn test_list() { 201 | let mut item = ListItem::create(1); 202 | assert_eq!(1, *item); 203 | let mut list = LinkedList::new(); 204 | list.push(&mut item); 205 | let head: &u32 = list.head_mut().unwrap(); 206 | assert_eq!(1, *head); 207 | let head: &u32 = list.pop().unwrap(); 208 | assert_eq!(1, *head); 209 | assert!(list.is_empty()); 210 | } 211 | 212 | #[test] 213 | fn test_iter() { 214 | let mut item1 = ListItem::create(9); 215 | let mut item2 = ListItem::create(1); 216 | let mut item3 = ListItem::create(3); 217 | let mut list = LinkedList::new(); 218 | list.push(&mut item1); 219 | list.push(&mut item2); 220 | list.push(&mut item3); 221 | let expected = [9, 1, 3]; 222 | for (i, item) in list.iter().enumerate() { 223 | assert_eq!(expected[i], *item); 224 | } 225 | } 226 | 227 | #[test] 228 | fn test_iter_mut() { 229 | let mut item1 = ListItem::create(7); 230 | let mut item2 = ListItem::create(5); 231 | let mut item3 = ListItem::create(3); 232 | let mut list = LinkedList::new(); 233 | list.push(&mut item1); 234 | list.push(&mut item2); 235 | list.push(&mut item3); 236 | let expected = [7, 5, 3]; 237 | let next = [3, 1, 5]; 238 | for (i, item) in list.iter_mut().enumerate() { 239 | assert_eq!(expected[i], *item); 240 | *item += next[i]; 241 | } 242 | for (i, item) in list.iter().enumerate() { 243 | assert_eq!(expected[i] + next[i], *item); 244 | } 245 | } 246 | 247 | #[test] 248 | fn test_join() { 249 | let mut list1 = LinkedList::new(); 250 | let mut list2 = LinkedList::new(); 251 | let mut item1 = ListItem::create(1); 252 | list1.push(&mut item1); 253 | let mut item2 = ListItem::create(3); 254 | list1.push(&mut item2); 255 | let mut item3 = ListItem::create(5); 256 | list1.push(&mut item3); 257 | let mut item4 = ListItem::create(2); 258 | list1.push(&mut item4); 259 | let mut item5 = ListItem::create(4); 260 | list1.push(&mut item5); 261 | list1.join(&mut list2); 262 | assert!(list2.is_empty()); 263 | let item: &u32 = list1.pop().unwrap(); 264 | assert_eq!(1, *(item)); 265 | let item: &u32 = list1.pop().unwrap(); 266 | assert_eq!(3, *(item)); 267 | let item: &u32 = list1.pop().unwrap(); 268 | assert_eq!(5, *(item)); 269 | let item: &u32 = list1.pop().unwrap(); 270 | assert_eq!(2, *(item)); 271 | let item: &u32 = list1.pop().unwrap(); 272 | assert_eq!(4, *(item)); 273 | assert!(list1.is_empty()); 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /util/src/sync.rs: -------------------------------------------------------------------------------- 1 | use lock_api::{RawMutex, GuardSend}; 2 | 3 | pub struct RawUnsafeLock {} 4 | 5 | unsafe impl RawMutex for RawUnsafeLock { 6 | const INIT: Self = Self {}; 7 | // A spinlock guard can be sent to another thread and unlocked there 8 | type GuardMarker = GuardSend; 9 | 10 | fn lock(&self) { 11 | } 12 | 13 | fn try_lock(&self) -> bool { 14 | true 15 | } 16 | 17 | unsafe fn unlock(&self) { 18 | } 19 | } 20 | 21 | pub type UnsafeLock = lock_api::Mutex; 22 | pub type UnsafeLockGuard<'a, T> = lock_api::MutexGuard<'a, RawUnsafeLock, T>; 23 | -------------------------------------------------------------------------------- /wio_app/.cargo/config: -------------------------------------------------------------------------------- 1 | [target.thumbv7em-none-eabihf] 2 | rustflags = [ 3 | "-C", "link-arg=-Tdevice.ld", 4 | "-C", "link-arg=-Tlink.ld", 5 | "-C", "link-arg=-Tlog.ld", 6 | ] 7 | 8 | [build] 9 | target = "thumbv7em-none-eabihf" 10 | -------------------------------------------------------------------------------- /wio_app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wio_app" 3 | version = "0.1.0" 4 | authors = ["garasubo "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | arch = { path = "../arch" } 11 | wio_terminal = { path = "../devices/wio_terminal" } 12 | rt = { path = "../rt" } 13 | log = { path = "../log" } 14 | kernel = { path = "../kernel" } 15 | user = { path = "../user" } 16 | util = { path = "../util" } 17 | cortex-m-semihosting = "0.3.5" 18 | embedded-hal = "0.2.2" 19 | -------------------------------------------------------------------------------- /wio_app/examples/led.rs: -------------------------------------------------------------------------------- 1 | #![feature(custom_test_frameworks)] 2 | #![test_runner(rt::test_runner)] 3 | #![reexport_test_harness_main = "test_main"] 4 | #![cfg_attr(test, no_main)] 5 | #![no_std] 6 | #![no_main] 7 | #![feature(asm)] 8 | 9 | use rt::entry; 10 | use wio_terminal::{button::{Button, UserButton1}, pin::Pin, port::Port}; 11 | use wio_terminal::led::Led; 12 | 13 | entry!(main); 14 | 15 | pub fn main() -> ! { 16 | let port_a = Port::new(); 17 | let port_c = Port::new(); 18 | let led = Led::init(&port_a); 19 | let pc26 = Pin::new(&port_c); 20 | let button1 = UserButton1::init(&pc26); 21 | 22 | loop { 23 | if button1.is_pressed() { 24 | led.set(); 25 | } else { 26 | led.clear(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /wio_app/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(custom_test_frameworks)] 2 | #![test_runner(rt::test_runner)] 3 | #![reexport_test_harness_main = "test_main"] 4 | #![cfg_attr(test, no_main)] 5 | #![no_std] 6 | #![no_main] 7 | #![feature(asm)] 8 | 9 | use rt::entry; 10 | use wio_terminal::port::Port; 11 | use wio_terminal::led::{Led, UserLed}; 12 | 13 | entry!(main); 14 | 15 | pub fn main() -> ! { 16 | let port_a = Port::new(); 17 | let led: UserLed = Led::init(&port_a); 18 | led.set(); 19 | 20 | loop {} 21 | } --------------------------------------------------------------------------------