commit
						18626a2a19
					
				@ -0,0 +1,235 @@
 | 
				
			|||||||
 | 
					# This file is automatically @generated by Cargo.
 | 
				
			||||||
 | 
					# It is not intended for manual editing.
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "aarch64"
 | 
				
			||||||
 | 
					version = "2.2.2"
 | 
				
			||||||
 | 
					source = "git+https://github.com/equation314/aarch64#14a08f4d285ae0ff515b03bff9f5e66eb68feaed"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "bcm2837"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					source = "git+https://github.com/equation314/bcm2837#446f0ea04deb5216ba5e08f10af36e5c1729e6fd"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "bit_field"
 | 
				
			||||||
 | 
					version = "0.9.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "bitflags"
 | 
				
			||||||
 | 
					version = "1.0.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cc"
 | 
				
			||||||
 | 
					version = "1.0.30"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "fixedvec"
 | 
				
			||||||
 | 
					version = "0.2.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "fuchsia-cprng"
 | 
				
			||||||
 | 
					version = "0.1.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "getopts"
 | 
				
			||||||
 | 
					version = "0.2.18"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "libc"
 | 
				
			||||||
 | 
					version = "0.2.50"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pulldown-cmark"
 | 
				
			||||||
 | 
					version = "0.0.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rand"
 | 
				
			||||||
 | 
					version = "0.4.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rand_core"
 | 
				
			||||||
 | 
					version = "0.3.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rand_core"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rcore-bootloader"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "aarch64 2.2.2 (git+https://github.com/equation314/aarch64)",
 | 
				
			||||||
 | 
					 "bcm2837 0.1.0 (git+https://github.com/equation314/bcm2837)",
 | 
				
			||||||
 | 
					 "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rdrand"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "register"
 | 
				
			||||||
 | 
					version = "0.2.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "remove_dir_all"
 | 
				
			||||||
 | 
					version = "0.5.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "skeptic"
 | 
				
			||||||
 | 
					version = "0.5.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tempdir"
 | 
				
			||||||
 | 
					version = "0.3.7"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tock-registers"
 | 
				
			||||||
 | 
					version = "0.2.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "unicode-width"
 | 
				
			||||||
 | 
					version = "0.1.5"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "usize_conversions"
 | 
				
			||||||
 | 
					version = "0.2.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "ux"
 | 
				
			||||||
 | 
					version = "0.1.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "volatile"
 | 
				
			||||||
 | 
					version = "0.2.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "winapi"
 | 
				
			||||||
 | 
					version = "0.3.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "winapi-i686-pc-windows-gnu"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "winapi-x86_64-pc-windows-gnu"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "xmas-elf"
 | 
				
			||||||
 | 
					version = "0.6.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zero"
 | 
				
			||||||
 | 
					version = "0.1.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[metadata]
 | 
				
			||||||
 | 
					"checksum aarch64 2.2.2 (git+https://github.com/equation314/aarch64)" = "<none>"
 | 
				
			||||||
 | 
					"checksum bcm2837 0.1.0 (git+https://github.com/equation314/bcm2837)" = "<none>"
 | 
				
			||||||
 | 
					"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
 | 
				
			||||||
 | 
					"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
 | 
				
			||||||
 | 
					"checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92"
 | 
				
			||||||
 | 
					"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
 | 
				
			||||||
 | 
					"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
 | 
				
			||||||
 | 
					"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
 | 
				
			||||||
 | 
					"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1"
 | 
				
			||||||
 | 
					"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
 | 
				
			||||||
 | 
					"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
 | 
				
			||||||
 | 
					"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
 | 
				
			||||||
 | 
					"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
 | 
				
			||||||
 | 
					"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
 | 
				
			||||||
 | 
					"checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb"
 | 
				
			||||||
 | 
					"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
 | 
				
			||||||
 | 
					"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c"
 | 
				
			||||||
 | 
					"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
 | 
				
			||||||
 | 
					"checksum tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316"
 | 
				
			||||||
 | 
					"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
 | 
				
			||||||
 | 
					"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
 | 
				
			||||||
 | 
					"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f"
 | 
				
			||||||
 | 
					"checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29"
 | 
				
			||||||
 | 
					"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
 | 
				
			||||||
 | 
					"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 | 
				
			||||||
 | 
					"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 | 
				
			||||||
 | 
					"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58"
 | 
				
			||||||
 | 
					"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5"
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "rcore-bootloader"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					authors = ["equation314 <equation618@gmail.com>"]
 | 
				
			||||||
 | 
					edition = "2018"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					xmas-elf = "0.6.2"
 | 
				
			||||||
 | 
					fixedvec = "0.2.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[target.'cfg(target_arch = "aarch64")'.dependencies]
 | 
				
			||||||
 | 
					aarch64 = { git = "https://github.com/equation314/aarch64" }
 | 
				
			||||||
 | 
					bcm2837 = { git = "https://github.com/equation314/bcm2837" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[build-dependencies]
 | 
				
			||||||
 | 
					cc = "1.0"
 | 
				
			||||||
@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					arch ?= aarch64
 | 
				
			||||||
 | 
					mode ?= debug
 | 
				
			||||||
 | 
					target := $(arch)
 | 
				
			||||||
 | 
					payload ?=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bootloader := target/$(target)/$(mode)/rcore-bootloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(arch), x86_64)
 | 
				
			||||||
 | 
					ifeq ($(uname), Darwin)
 | 
				
			||||||
 | 
					prefix := x86_64-elf-
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					else ifeq ($(arch), riscv32)
 | 
				
			||||||
 | 
					prefix := riscv64-unknown-elf-
 | 
				
			||||||
 | 
					else ifeq ($(arch), riscv64)
 | 
				
			||||||
 | 
					prefix := riscv64-unknown-elf-
 | 
				
			||||||
 | 
					else ifeq ($(arch), aarch64)
 | 
				
			||||||
 | 
					prefix ?= aarch64-none-elf-
 | 
				
			||||||
 | 
					ifeq (,$(shell which $(prefix)ld))
 | 
				
			||||||
 | 
						prefix := aarch64-elf-
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ld := $(prefix)ld
 | 
				
			||||||
 | 
					objdump := $(prefix)objdump
 | 
				
			||||||
 | 
					objcopy := $(prefix)objcopy
 | 
				
			||||||
 | 
					cc := $(prefix)gcc
 | 
				
			||||||
 | 
					as := $(prefix)as
 | 
				
			||||||
 | 
					gdb := $(prefix)gdb
 | 
				
			||||||
 | 
					strip := $(prefix)strip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export CC = $(cc)
 | 
				
			||||||
 | 
					export PAYLOAD = $(payload)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					build_args := --target=targets/$(arch).json
 | 
				
			||||||
 | 
					ifeq ($(mode), release)
 | 
				
			||||||
 | 
					build_args += --release
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: all clean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: bootloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bootloader: $(payload)
 | 
				
			||||||
 | 
						@cargo xbuild $(build_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						@cargo clean
 | 
				
			||||||
@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					extern crate cc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::fs::File;
 | 
				
			||||||
 | 
					use std::io::{Result, Write};
 | 
				
			||||||
 | 
					use std::path::Path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    if let Ok(file_path) = gen_payload_asm() {
 | 
				
			||||||
 | 
					        cc::Build::new().file(&file_path).compile("payload");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn gen_payload_asm() -> Result<std::path::PathBuf> {
 | 
				
			||||||
 | 
					    let out_dir = std::env::var("OUT_DIR").unwrap();
 | 
				
			||||||
 | 
					    let payload = std::env::var("PAYLOAD").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !Path::new(&payload).is_file() {
 | 
				
			||||||
 | 
					        panic!("Kernel payload `{}` not found", payload)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let file_path = Path::new(&out_dir).join("payload.S");
 | 
				
			||||||
 | 
					    let mut f = File::create(&file_path).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("{:x?} {:x?}", payload, file_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write!(f, "# generated by build.rs - do not edit")?;
 | 
				
			||||||
 | 
					    write!(f, r#"
 | 
				
			||||||
 | 
					    .section .payload,"a"
 | 
				
			||||||
 | 
					    .align 12
 | 
				
			||||||
 | 
					    .global _kernel_payload_start, _kernel_payload_end
 | 
				
			||||||
 | 
					_kernel_payload_start:
 | 
				
			||||||
 | 
					    .incbin "{}"
 | 
				
			||||||
 | 
					_kernel_payload_end:
 | 
				
			||||||
 | 
					"#, payload)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("cargo:rerun-if-changed={}", payload);
 | 
				
			||||||
 | 
					    println!("cargo:rerun-if-env-changed=PAYLOAD");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(file_path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					ENTRY(_start)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SECTIONS {
 | 
				
			||||||
 | 
					  . = 0x80000; /* Raspbery Pi 3 AArch64 (kernel8.img) load address */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .text : {
 | 
				
			||||||
 | 
					    KEEP(*(.text.boot)) /* from boot.S */
 | 
				
			||||||
 | 
					    *(.text .text.* .gnu.linkonce.t*)
 | 
				
			||||||
 | 
					    . = ALIGN(4K);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .rodata : {
 | 
				
			||||||
 | 
					    *(.rodata .rodata.* .gnu.linkonce.r*)
 | 
				
			||||||
 | 
					    . = ALIGN(4K);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .data : {
 | 
				
			||||||
 | 
					    *(.data .data.* .gnu.linkonce.d*)
 | 
				
			||||||
 | 
					    . = ALIGN(4K);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .bss : {
 | 
				
			||||||
 | 
					    _sbss = .;
 | 
				
			||||||
 | 
					    *(.bss .bss.*)
 | 
				
			||||||
 | 
					    *(COMMON)
 | 
				
			||||||
 | 
					    . = ALIGN(4K);
 | 
				
			||||||
 | 
					    _ebss = .;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .payload : {
 | 
				
			||||||
 | 
					    *(.payload)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					use aarch64::addr::{VirtAddr, PhysAddr};
 | 
				
			||||||
 | 
					use aarch64::paging::{memory_attribute::*, Page, PageTable, PageTableFlags as EF, PhysFrame};
 | 
				
			||||||
 | 
					use aarch64::paging::{Size4KiB, Size2MiB, Size1GiB};
 | 
				
			||||||
 | 
					use aarch64::{asm::*, barrier, regs::*};
 | 
				
			||||||
 | 
					use bcm2837::consts::RAW_IO_BASE;
 | 
				
			||||||
 | 
					use core::ptr;
 | 
				
			||||||
 | 
					use fixedvec::FixedVec;
 | 
				
			||||||
 | 
					use xmas_elf::program::{ProgramHeader64, Type};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PAGE_SIZE: usize = 4096;
 | 
				
			||||||
 | 
					const ALIGN_2MB: u64 = 0x200000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RECURSIVE_INDEX: usize = 0o777;
 | 
				
			||||||
 | 
					const KERNEL_OFFSET: u64 = 0xFFFF_0000_0000_0000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					global_asm!(include_str!("boot.S"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_temp_page_table(start_vaddr: VirtAddr, end_vaddr: VirtAddr, offset: u64) {
 | 
				
			||||||
 | 
					    #[repr(align(4096))]
 | 
				
			||||||
 | 
					    struct PageData([u8; PAGE_SIZE]);
 | 
				
			||||||
 | 
					    static mut PAGE_TABLE_LVL4: PageData = PageData([0; PAGE_SIZE]);
 | 
				
			||||||
 | 
					    static mut PAGE_TABLE_LVL3: PageData = PageData([0; PAGE_SIZE]);
 | 
				
			||||||
 | 
					    static mut PAGE_TABLE_LVL2: PageData = PageData([0; PAGE_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let frame_lvl4 = unsafe { PhysFrame::<Size4KiB>::containing_address(PhysAddr::new(&PAGE_TABLE_LVL4 as *const _ as u64)) };
 | 
				
			||||||
 | 
					    let frame_lvl3 = unsafe { PhysFrame::<Size4KiB>::containing_address(PhysAddr::new(&PAGE_TABLE_LVL3 as *const _ as u64)) };
 | 
				
			||||||
 | 
					    let frame_lvl2 = unsafe { PhysFrame::<Size4KiB>::containing_address(PhysAddr::new(&PAGE_TABLE_LVL2 as *const _ as u64)) };
 | 
				
			||||||
 | 
					    let p4 = unsafe { &mut *(frame_lvl4.start_address().as_u64() as *mut PageTable) };
 | 
				
			||||||
 | 
					    let p3 = unsafe { &mut *(frame_lvl3.start_address().as_u64() as *mut PageTable) };
 | 
				
			||||||
 | 
					    let p2 = unsafe { &mut *(frame_lvl2.start_address().as_u64() as *mut PageTable) };
 | 
				
			||||||
 | 
					    p4.zero();
 | 
				
			||||||
 | 
					    p3.zero();
 | 
				
			||||||
 | 
					    p2.zero();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let block_flags = EF::VALID | EF::AF | EF::WRITE | EF::UXN;
 | 
				
			||||||
 | 
					    // normal memory
 | 
				
			||||||
 | 
					    for page in Page::<Size2MiB>::range_of(start_vaddr.as_u64(), end_vaddr.as_u64()) {
 | 
				
			||||||
 | 
					        let paddr = PhysAddr::new(page.start_address().as_u64().wrapping_add(offset));
 | 
				
			||||||
 | 
					        p2[page.p2_index()].set_block::<Size2MiB>(paddr, block_flags, MairNormal::attr_value());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // device memory
 | 
				
			||||||
 | 
					    for page in Page::<Size2MiB>::range_of(RAW_IO_BASE as u64, 0x4000_0000) {
 | 
				
			||||||
 | 
					        let paddr = PhysAddr::new(page.start_address().as_u64());
 | 
				
			||||||
 | 
					        p2[page.p2_index()].set_block::<Size2MiB>(paddr, block_flags | EF::PXN, MairDevice::attr_value());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p3[0].set_frame(frame_lvl2, EF::default(), MairNormal::attr_value());
 | 
				
			||||||
 | 
					    p3[1].set_block::<Size1GiB>(PhysAddr::new(0x4000_0000), block_flags | EF::PXN, MairDevice::attr_value());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p4[0].set_frame(frame_lvl3, EF::default(), MairNormal::attr_value());
 | 
				
			||||||
 | 
					    p4[RECURSIVE_INDEX].set_frame(frame_lvl4, EF::default(), MairNormal::attr_value());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ttbr_el1_write(0, frame_lvl4);
 | 
				
			||||||
 | 
					    ttbr_el1_write(1, frame_lvl4);
 | 
				
			||||||
 | 
					    tlb_invalidate_all();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn enable_mmu() {
 | 
				
			||||||
 | 
					    MAIR_EL1.write(
 | 
				
			||||||
 | 
					        MAIR_EL1::Attr0.val(MairNormal::config_value()) +
 | 
				
			||||||
 | 
					        MAIR_EL1::Attr1.val(MairDevice::config_value()) +
 | 
				
			||||||
 | 
					        MAIR_EL1::Attr2.val(MairNormalNonCacheable::config_value()),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Configure various settings of stage 1 of the EL1 translation regime.
 | 
				
			||||||
 | 
					    let ips = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange);
 | 
				
			||||||
 | 
					    TCR_EL1.write(
 | 
				
			||||||
 | 
					        TCR_EL1::TBI1::Ignored +
 | 
				
			||||||
 | 
					        TCR_EL1::TBI0::Ignored +
 | 
				
			||||||
 | 
					        TCR_EL1::AS::Bits_16 +
 | 
				
			||||||
 | 
					        TCR_EL1::IPS.val(ips) +
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TCR_EL1::TG1::KiB_4 +
 | 
				
			||||||
 | 
					        TCR_EL1::SH1::Inner +
 | 
				
			||||||
 | 
					        TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
 | 
				
			||||||
 | 
					        TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
 | 
				
			||||||
 | 
					        TCR_EL1::EPD1::EnableTTBR1Walks +
 | 
				
			||||||
 | 
					        TCR_EL1::A1::UseTTBR1ASID +
 | 
				
			||||||
 | 
					        TCR_EL1::T1SZ.val(16) +
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TCR_EL1::TG0::KiB_4 +
 | 
				
			||||||
 | 
					        TCR_EL1::SH0::Inner +
 | 
				
			||||||
 | 
					        TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
 | 
				
			||||||
 | 
					        TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
 | 
				
			||||||
 | 
					        TCR_EL1::EPD0::EnableTTBR0Walks +
 | 
				
			||||||
 | 
					        TCR_EL1::T0SZ.val(16),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Switch the MMU on.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // First, force all previous changes to be seen before the MMU is enabled.
 | 
				
			||||||
 | 
					    unsafe { barrier::isb(barrier::SY) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Enable the MMU and turn on data and instruction caching.
 | 
				
			||||||
 | 
					    SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Force MMU init to complete before next instruction
 | 
				
			||||||
 | 
					    unsafe { barrier::isb(barrier::SY) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn map_kernel(kernel_start: usize, segments: &FixedVec<ProgramHeader64>) {
 | 
				
			||||||
 | 
					    // reverse program headers to avoid overlapping in memory copying
 | 
				
			||||||
 | 
					    let mut space = alloc_stack!([ProgramHeader64; 32]);
 | 
				
			||||||
 | 
					    let mut rev_segments = FixedVec::new(&mut space);
 | 
				
			||||||
 | 
					    for i in (0..segments.len()).rev() {
 | 
				
			||||||
 | 
					        rev_segments.push(segments[i]).unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let (mut start_vaddr, mut end_vaddr) = (VirtAddr::new(core::u64::MAX), VirtAddr::zero());
 | 
				
			||||||
 | 
					    for segment in &rev_segments {
 | 
				
			||||||
 | 
					        if segment.get_type() != Ok(Type::Load) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let virt_addr = segment.virtual_addr;
 | 
				
			||||||
 | 
					        let offset = segment.offset;
 | 
				
			||||||
 | 
					        let file_size = segment.file_size;
 | 
				
			||||||
 | 
					        let mem_size = segment.mem_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            let src = (kernel_start as u64 + offset) as *const u8;
 | 
				
			||||||
 | 
					            let dst = virt_addr.wrapping_sub(KERNEL_OFFSET) as *mut u8;
 | 
				
			||||||
 | 
					            ptr::copy(src, dst, file_size as usize);
 | 
				
			||||||
 | 
					            ptr::write_bytes(dst.offset(file_size as isize), 0, (mem_size - file_size) as usize);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if virt_addr < start_vaddr.as_u64() {
 | 
				
			||||||
 | 
					            start_vaddr = VirtAddr::new(virt_addr).align_down(ALIGN_2MB);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if virt_addr + mem_size > end_vaddr.as_u64() {
 | 
				
			||||||
 | 
					            end_vaddr = VirtAddr::new(virt_addr + mem_size).align_up(ALIGN_2MB);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setup_temp_page_table(start_vaddr, end_vaddr, KERNEL_OFFSET.wrapping_neg());
 | 
				
			||||||
 | 
					    enable_mmu();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					use core::panic::PanicInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[panic_handler]
 | 
				
			||||||
 | 
					#[no_mangle]
 | 
				
			||||||
 | 
					pub extern "C" fn panic(_info: &PanicInfo) -> ! {
 | 
				
			||||||
 | 
					    loop {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					#![feature(lang_items)]
 | 
				
			||||||
 | 
					#![feature(global_asm)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[macro_use]
 | 
				
			||||||
 | 
					extern crate fixedvec;
 | 
				
			||||||
 | 
					extern crate xmas_elf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use core::mem::transmute;
 | 
				
			||||||
 | 
					use core::slice;
 | 
				
			||||||
 | 
					use fixedvec::FixedVec;
 | 
				
			||||||
 | 
					use xmas_elf::{
 | 
				
			||||||
 | 
					    header,
 | 
				
			||||||
 | 
					    program::{ProgramHeader, ProgramHeader64},
 | 
				
			||||||
 | 
					    ElfFile,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(target_arch = "aarch64")]
 | 
				
			||||||
 | 
					#[path = "arch/aarch64/mod.rs"]
 | 
				
			||||||
 | 
					pub mod arch;
 | 
				
			||||||
 | 
					pub mod lang_items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					    fn _kernel_payload_start();
 | 
				
			||||||
 | 
					    fn _kernel_payload_end();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The entry point of bootloader
 | 
				
			||||||
 | 
					#[no_mangle] // don't mangle the name of this function
 | 
				
			||||||
 | 
					pub extern "C" fn boot_main() -> ! {
 | 
				
			||||||
 | 
					    let kernel_size = _kernel_payload_end as usize - _kernel_payload_start as usize;
 | 
				
			||||||
 | 
					    let kernel = unsafe { slice::from_raw_parts(_kernel_payload_start as *const u8, kernel_size) };
 | 
				
			||||||
 | 
					    let kernel_elf = ElfFile::new(kernel).unwrap();
 | 
				
			||||||
 | 
					    header::sanity_check(&kernel_elf).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut preallocated_space = alloc_stack!([ProgramHeader64; 32]);
 | 
				
			||||||
 | 
					    let mut segments = FixedVec::new(&mut preallocated_space);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for program_header in kernel_elf.program_iter() {
 | 
				
			||||||
 | 
					        match program_header {
 | 
				
			||||||
 | 
					            ProgramHeader::Ph64(header) => segments
 | 
				
			||||||
 | 
					                .push(*header)
 | 
				
			||||||
 | 
					                .expect("does not support more than 32 program segments"),
 | 
				
			||||||
 | 
					            ProgramHeader::Ph32(_) => panic!("does not support 32 bit elf files"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let entry = kernel_elf.header.pt2.entry_point();
 | 
				
			||||||
 | 
					    let kernel_main: extern "C" fn() = unsafe { transmute(entry) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch::map_kernel(_kernel_payload_start as usize, &segments);
 | 
				
			||||||
 | 
					    kernel_main();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "abi-blacklist": [
 | 
				
			||||||
 | 
					    "stdcall",
 | 
				
			||||||
 | 
					    "fastcall",
 | 
				
			||||||
 | 
					    "vectorcall",
 | 
				
			||||||
 | 
					    "thiscall",
 | 
				
			||||||
 | 
					    "win64",
 | 
				
			||||||
 | 
					    "sysv64"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "arch": "aarch64",
 | 
				
			||||||
 | 
					  "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
 | 
				
			||||||
 | 
					  "executables": true,
 | 
				
			||||||
 | 
					  "linker": "rust-lld",
 | 
				
			||||||
 | 
					  "linker-flavor": "ld.lld",
 | 
				
			||||||
 | 
					  "linker-is-gnu": true,
 | 
				
			||||||
 | 
					  "pre-link-args": {
 | 
				
			||||||
 | 
					    "ld.lld": [
 | 
				
			||||||
 | 
					      "-Tsrc/arch/aarch64/boot.ld"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "llvm-target": "aarch64-unknown-none",
 | 
				
			||||||
 | 
					  "no-compiler-rt": true,
 | 
				
			||||||
 | 
					  "features": "+a53,+strict-align,-neon",
 | 
				
			||||||
 | 
					  "max-atomic-width": 128,
 | 
				
			||||||
 | 
					  "os": "none",
 | 
				
			||||||
 | 
					  "panic": "abort",
 | 
				
			||||||
 | 
					  "panic-strategy": "abort",
 | 
				
			||||||
 | 
					  "relocation-model": "static",
 | 
				
			||||||
 | 
					  "position-independent-executables": true,
 | 
				
			||||||
 | 
					  "target-c-int-width": "32",
 | 
				
			||||||
 | 
					  "target-endian": "little",
 | 
				
			||||||
 | 
					  "target-pointer-width": "64",
 | 
				
			||||||
 | 
					  "target-family": "unix",
 | 
				
			||||||
 | 
					  "disable-redzone": true,
 | 
				
			||||||
 | 
					  "eliminate-frame-pointer": false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,6 +0,0 @@
 | 
				
			|||||||
[package]
 | 
					 | 
				
			||||||
name = "atags"
 | 
					 | 
				
			||||||
version = "0.1.0"
 | 
					 | 
				
			||||||
authors = ["koumingyang <1761674434@qq.com>"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
@ -1,67 +0,0 @@
 | 
				
			|||||||
use raw;
 | 
					 | 
				
			||||||
use core::slice;
 | 
					 | 
				
			||||||
use core::str;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub use raw::{Core, Mem};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// An ATAG.
 | 
					 | 
				
			||||||
#[derive(Debug, Copy, Clone)]
 | 
					 | 
				
			||||||
pub enum Atag {
 | 
					 | 
				
			||||||
    Core(raw::Core),
 | 
					 | 
				
			||||||
    Mem(raw::Mem),
 | 
					 | 
				
			||||||
    Cmd(&'static str),
 | 
					 | 
				
			||||||
    Unknown(u32),
 | 
					 | 
				
			||||||
    None
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Atag {
 | 
					 | 
				
			||||||
    /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
 | 
					 | 
				
			||||||
    pub fn core(self) -> Option<Core> {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Atag::Core(x) => Some(x),
 | 
					 | 
				
			||||||
            _ => None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Returns `Some` if this is a `Mem` ATAG. Otherwise returns `None`.
 | 
					 | 
				
			||||||
    pub fn mem(self) -> Option<Mem> {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Atag::Mem(x) => Some(x),
 | 
					 | 
				
			||||||
            _ => None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Returns `Some` with the command line string if this is a `Cmd` ATAG.
 | 
					 | 
				
			||||||
    /// Otherwise returns `None`.
 | 
					 | 
				
			||||||
    pub fn cmd(self) -> Option<&'static str> {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Atag::Cmd(x) => Some(x),
 | 
					 | 
				
			||||||
            _ => None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Convert between raw::* types and Atag wrapper.
 | 
					 | 
				
			||||||
impl<'a> From<&'a raw::Atag> for Atag {
 | 
					 | 
				
			||||||
    fn from(atag: &raw::Atag) -> Atag {
 | 
					 | 
				
			||||||
        unsafe {
 | 
					 | 
				
			||||||
            match (atag.tag, &atag.kind) {
 | 
					 | 
				
			||||||
                (raw::Atag::CORE, &raw::Kind { core }) => Atag::Core(core),
 | 
					 | 
				
			||||||
                (raw::Atag::MEM, &raw::Kind { mem }) => Atag::Mem(mem),
 | 
					 | 
				
			||||||
                (raw::Atag::CMDLINE, &raw::Kind { ref cmd }) => {
 | 
					 | 
				
			||||||
                    let mut cmd_ptr: *const u8 = &cmd.cmd as *const u8;
 | 
					 | 
				
			||||||
                    let mut len: usize = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    while *cmd_ptr.add(len) != 0 {
 | 
					 | 
				
			||||||
                        len += 1;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    let cmd_slice = slice::from_raw_parts(cmd_ptr, len);
 | 
					 | 
				
			||||||
                    Atag::Cmd(str::from_utf8_unchecked(cmd_slice))
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                (raw::Atag::NONE, _) => Atag::None,
 | 
					 | 
				
			||||||
                (id, _) => Atag::Unknown(id),
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,37 +0,0 @@
 | 
				
			|||||||
pub use atag::*;
 | 
					 | 
				
			||||||
use raw;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The address at which the firmware loads the ATAGS.
 | 
					 | 
				
			||||||
const ATAG_BASE: usize = 0x100;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// An iterator over the ATAGS on this system.
 | 
					 | 
				
			||||||
pub struct Atags {
 | 
					 | 
				
			||||||
    ptr: &'static raw::Atag,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Atags {
 | 
					 | 
				
			||||||
    /// Returns an instance of `Atags`, an iterator over ATAGS on this system.
 | 
					 | 
				
			||||||
    pub fn get() -> Atags {
 | 
					 | 
				
			||||||
        Atags {
 | 
					 | 
				
			||||||
            ptr: unsafe { &*(ATAG_BASE as *const raw::Atag) }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Iterator for Atags {
 | 
					 | 
				
			||||||
    type Item = Atag;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Iterate over Atags.  Returns a valid Atag until the iterator hits the
 | 
					 | 
				
			||||||
    /// Atag::None.
 | 
					 | 
				
			||||||
    fn next(&mut self) -> Option<Atag> {
 | 
					 | 
				
			||||||
        let cur = self.ptr;
 | 
					 | 
				
			||||||
        match cur.next() {
 | 
					 | 
				
			||||||
            Some(next) => {
 | 
					 | 
				
			||||||
                let result = Some(Atag::from(cur));
 | 
					 | 
				
			||||||
                self.ptr = next;
 | 
					 | 
				
			||||||
                result
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            None => None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,6 +0,0 @@
 | 
				
			|||||||
#![no_std]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod raw;
 | 
					 | 
				
			||||||
mod atag;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub mod atags;
 | 
					 | 
				
			||||||
@ -1,67 +0,0 @@
 | 
				
			|||||||
/// A raw `ATAG` as laid out in memory.
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
pub struct Atag {
 | 
					 | 
				
			||||||
    pub dwords: u32,
 | 
					 | 
				
			||||||
    pub tag: u32,
 | 
					 | 
				
			||||||
    pub kind: Kind
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Atag {
 | 
					 | 
				
			||||||
    pub const NONE: u32 = 0x00000000;
 | 
					 | 
				
			||||||
    pub const CORE: u32 = 0x54410001;
 | 
					 | 
				
			||||||
    pub const MEM: u32 = 0x54410002;
 | 
					 | 
				
			||||||
    pub const VIDEOTEXT: u32 = 0x54410003;
 | 
					 | 
				
			||||||
    pub const RAMDISK: u32 = 0x54410004;
 | 
					 | 
				
			||||||
    pub const INITRD2: u32 = 0x54420005;
 | 
					 | 
				
			||||||
    pub const SERIAL: u32 = 0x54410006;
 | 
					 | 
				
			||||||
    pub const REVISION: u32 = 0x54410007;
 | 
					 | 
				
			||||||
    pub const VIDEOLFB: u32 = 0x54410008;
 | 
					 | 
				
			||||||
    pub const CMDLINE: u32 = 0x54410009;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Returns the ATAG following `self`, if there is one.
 | 
					 | 
				
			||||||
    pub fn next(&self) -> Option<&Atag> {
 | 
					 | 
				
			||||||
        if self.tag == Atag::NONE {
 | 
					 | 
				
			||||||
            None
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            let current = self as *const Atag as *const u32;
 | 
					 | 
				
			||||||
            let next: &Atag = unsafe {
 | 
					 | 
				
			||||||
                &*(current.add(self.dwords as usize) as *const Atag)
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Some(next)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The possible variant of an ATAG.
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
pub union Kind {
 | 
					 | 
				
			||||||
    pub core: Core,
 | 
					 | 
				
			||||||
    pub mem: Mem,
 | 
					 | 
				
			||||||
    pub cmd: Cmd
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A `CORE` ATAG.
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[derive(Debug, Copy, Clone)]
 | 
					 | 
				
			||||||
pub struct Core {
 | 
					 | 
				
			||||||
    pub flags: u32,
 | 
					 | 
				
			||||||
    pub page_size: u32,
 | 
					 | 
				
			||||||
    pub root_dev: u32
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A `MEM` ATAG.
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[derive(Debug, Copy, Clone)]
 | 
					 | 
				
			||||||
pub struct Mem {
 | 
					 | 
				
			||||||
    pub size: u32,
 | 
					 | 
				
			||||||
    pub start: u32
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A `CMDLINE` ATAG.
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[derive(Debug, Copy, Clone)]
 | 
					 | 
				
			||||||
pub struct Cmd {
 | 
					 | 
				
			||||||
    /// The first byte of the command line string.
 | 
					 | 
				
			||||||
    pub cmd: u8
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,12 +0,0 @@
 | 
				
			|||||||
[package]
 | 
					 | 
				
			||||||
name = "bcm2837"
 | 
					 | 
				
			||||||
version = "0.1.0"
 | 
					 | 
				
			||||||
authors = ["equation314 <equation618@gmail.com>"]
 | 
					 | 
				
			||||||
edition = "2018"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[features]
 | 
					 | 
				
			||||||
use_generic_timer = ["aarch64"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
volatile = "0.2.4"
 | 
					 | 
				
			||||||
aarch64= { git = "https://github.com/equation314/aarch64", optional = true }
 | 
					 | 
				
			||||||
@ -1,163 +0,0 @@
 | 
				
			|||||||
use crate::IO_BASE;
 | 
					 | 
				
			||||||
use crate::timer::delay;
 | 
					 | 
				
			||||||
use core::marker::PhantomData;
 | 
					 | 
				
			||||||
use volatile::{ReadOnly, Volatile, WriteOnly};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The base address of the `GPIO` registers.
 | 
					 | 
				
			||||||
const GPIO_BASE: usize = IO_BASE + 0x200000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// An alternative GPIO function. (ref: peripherals 6.1, page 92)
 | 
					 | 
				
			||||||
#[repr(u8)]
 | 
					 | 
				
			||||||
pub enum Function {
 | 
					 | 
				
			||||||
    Input = 0b000,
 | 
					 | 
				
			||||||
    Output = 0b001,
 | 
					 | 
				
			||||||
    Alt0 = 0b100,
 | 
					 | 
				
			||||||
    Alt1 = 0b101,
 | 
					 | 
				
			||||||
    Alt2 = 0b110,
 | 
					 | 
				
			||||||
    Alt3 = 0b111,
 | 
					 | 
				
			||||||
    Alt4 = 0b011,
 | 
					 | 
				
			||||||
    Alt5 = 0b010,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// GPIO registers starting from `GPIO_BASE` (ref: peripherals 6.1, page 90)
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[allow(non_snake_case)]
 | 
					 | 
				
			||||||
struct Registers {
 | 
					 | 
				
			||||||
    FSEL: [Volatile<u32>; 6],
 | 
					 | 
				
			||||||
    __reserved0: u32,
 | 
					 | 
				
			||||||
    SET: [WriteOnly<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved1: u32,
 | 
					 | 
				
			||||||
    CLR: [WriteOnly<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved2: u32,
 | 
					 | 
				
			||||||
    LEV: [ReadOnly<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved3: u32,
 | 
					 | 
				
			||||||
    EDS: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved4: u32,
 | 
					 | 
				
			||||||
    REN: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved5: u32,
 | 
					 | 
				
			||||||
    FEN: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved6: u32,
 | 
					 | 
				
			||||||
    HEN: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved7: u32,
 | 
					 | 
				
			||||||
    LEN: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved8: u32,
 | 
					 | 
				
			||||||
    AREN: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved9: u32,
 | 
					 | 
				
			||||||
    AFEN: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    __reserved10: u32,
 | 
					 | 
				
			||||||
    PUD: Volatile<u32>,
 | 
					 | 
				
			||||||
    PUDCLK: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Possible states for a GPIO pin.
 | 
					 | 
				
			||||||
pub enum Uninitialized {}
 | 
					 | 
				
			||||||
pub enum Input {}
 | 
					 | 
				
			||||||
pub enum Output {}
 | 
					 | 
				
			||||||
pub enum Alt {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A GPIO pin in state `State`.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The `State` generic always corresponds to an uninstantiatable type that is
 | 
					 | 
				
			||||||
/// use solely to mark and track the state of a given GPIO pin. A `Gpio`
 | 
					 | 
				
			||||||
/// structure starts in the `Uninitialized` state and must be transitions into
 | 
					 | 
				
			||||||
/// one of `Input`, `Output`, or `Alt` via the `into_input`, `into_output`, and
 | 
					 | 
				
			||||||
/// `into_alt` methods before it can be used.
 | 
					 | 
				
			||||||
pub struct Gpio<State> {
 | 
					 | 
				
			||||||
    pin: u8,
 | 
					 | 
				
			||||||
    registers: &'static mut Registers,
 | 
					 | 
				
			||||||
    _state: PhantomData<State>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T> Gpio<T> {
 | 
					 | 
				
			||||||
    /// Transitions `self` to state `S`, consuming `self` and returning a new
 | 
					 | 
				
			||||||
    /// `Gpio` instance in state `S`. This method should _never_ be exposed to
 | 
					 | 
				
			||||||
    /// the public!
 | 
					 | 
				
			||||||
    #[inline(always)]
 | 
					 | 
				
			||||||
    fn transition<S>(self) -> Gpio<S> {
 | 
					 | 
				
			||||||
        Gpio {
 | 
					 | 
				
			||||||
            pin: self.pin,
 | 
					 | 
				
			||||||
            registers: self.registers,
 | 
					 | 
				
			||||||
            _state: PhantomData,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Set the Gpio pull-up/pull-down state for values in `pin_value`
 | 
					 | 
				
			||||||
    /// (ref: peripherals 6.1, page 101)
 | 
					 | 
				
			||||||
    pub fn set_gpio_pd(&mut self, pud_value: u8) {
 | 
					 | 
				
			||||||
        let index = if self.pin >= 32 { 1 } else { 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.registers.PUD.write(pud_value as u32);
 | 
					 | 
				
			||||||
        delay(150);
 | 
					 | 
				
			||||||
        self.registers.PUDCLK[index as usize].write((1 << self.pin) as u32);
 | 
					 | 
				
			||||||
        delay(150);
 | 
					 | 
				
			||||||
        self.registers.PUD.write(0);
 | 
					 | 
				
			||||||
        self.registers.PUDCLK[index as usize].write(0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Gpio<Uninitialized> {
 | 
					 | 
				
			||||||
    /// Returns a new `GPIO` structure for pin number `pin`.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// # Panics
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// Panics if `pin` > `53`.
 | 
					 | 
				
			||||||
    pub fn new(pin: u8) -> Gpio<Uninitialized> {
 | 
					 | 
				
			||||||
        if pin > 53 {
 | 
					 | 
				
			||||||
            panic!("Gpio::new(): pin {} exceeds maximum of 53", pin);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Gpio {
 | 
					 | 
				
			||||||
            registers: unsafe { &mut *(GPIO_BASE as *mut Registers) },
 | 
					 | 
				
			||||||
            pin: pin,
 | 
					 | 
				
			||||||
            _state: PhantomData,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Enables the alternative function `function` for `self`. Consumes self
 | 
					 | 
				
			||||||
    /// and returns a `Gpio` structure in the `Alt` state.
 | 
					 | 
				
			||||||
    pub fn into_alt(self, function: Function) -> Gpio<Alt> {
 | 
					 | 
				
			||||||
        let select = (self.pin / 10) as usize;
 | 
					 | 
				
			||||||
        let offset = 3 * (self.pin % 10) as usize;
 | 
					 | 
				
			||||||
        self.registers.FSEL[select].update(|value| {
 | 
					 | 
				
			||||||
            *value &= !(0b111 << offset);
 | 
					 | 
				
			||||||
            *value |= (function as u32) << offset;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        self.transition()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Sets this pin to be an _output_ pin. Consumes self and returns a `Gpio`
 | 
					 | 
				
			||||||
    /// structure in the `Output` state.
 | 
					 | 
				
			||||||
    pub fn into_output(self) -> Gpio<Output> {
 | 
					 | 
				
			||||||
        self.into_alt(Function::Output).transition()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Sets this pin to be an _input_ pin. Consumes self and returns a `Gpio`
 | 
					 | 
				
			||||||
    /// structure in the `Input` state.
 | 
					 | 
				
			||||||
    pub fn into_input(self) -> Gpio<Input> {
 | 
					 | 
				
			||||||
        self.into_alt(Function::Input).transition()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Gpio<Output> {
 | 
					 | 
				
			||||||
    /// Sets (turns on) the pin.
 | 
					 | 
				
			||||||
    pub fn set(&mut self) {
 | 
					 | 
				
			||||||
        let index = if self.pin >= 32 { 1 } else { 0 };
 | 
					 | 
				
			||||||
        self.registers.SET[index as usize].write(1 << (self.pin - index * 32));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Clears (turns off) the pin.
 | 
					 | 
				
			||||||
    pub fn clear(&mut self) {
 | 
					 | 
				
			||||||
        let index = if self.pin >= 32 { 1 } else { 0 };
 | 
					 | 
				
			||||||
        self.registers.CLR[index as usize].write(1 << (self.pin - index * 32));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Gpio<Input> {
 | 
					 | 
				
			||||||
    /// Reads the pin's value. Returns `true` if the level is high and `false`
 | 
					 | 
				
			||||||
    /// if the level is low.
 | 
					 | 
				
			||||||
    pub fn level(&mut self) -> bool {
 | 
					 | 
				
			||||||
        let index = if self.pin >= 32 { 1 } else { 0 };
 | 
					 | 
				
			||||||
        let high = 1 << (self.pin - index * 32);
 | 
					 | 
				
			||||||
        (self.registers.LEV[index as usize].read() & high) == high
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,88 +0,0 @@
 | 
				
			|||||||
use crate::IO_BASE;
 | 
					 | 
				
			||||||
use volatile::{ReadOnly, Volatile};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Allowed interrupts (ref: peripherals 7.5, page 113)
 | 
					 | 
				
			||||||
#[repr(u8)]
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, PartialEq, Debug)]
 | 
					 | 
				
			||||||
pub enum Interrupt {
 | 
					 | 
				
			||||||
    Timer1 = 1,
 | 
					 | 
				
			||||||
    Timer3 = 3,
 | 
					 | 
				
			||||||
    Usb = 9,
 | 
					 | 
				
			||||||
    Aux = 29,
 | 
					 | 
				
			||||||
    Gpio0 = 49,
 | 
					 | 
				
			||||||
    Gpio1 = 50,
 | 
					 | 
				
			||||||
    Gpio2 = 51,
 | 
					 | 
				
			||||||
    Gpio3 = 52,
 | 
					 | 
				
			||||||
    Uart = 57,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Interrupts registers starting from `INT_BASE` (ref: peripherals 7.5, page 112)
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[allow(non_snake_case)]
 | 
					 | 
				
			||||||
struct Registers {
 | 
					 | 
				
			||||||
    IRQBasicPending: ReadOnly<u32>,
 | 
					 | 
				
			||||||
    IRQPending: [ReadOnly<u32>; 2],
 | 
					 | 
				
			||||||
    FIQControl: Volatile<u32>,
 | 
					 | 
				
			||||||
    EnableIRQ: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    EnableBasicIRQ: Volatile<u32>,
 | 
					 | 
				
			||||||
    DisableIRQ: [Volatile<u32>; 2],
 | 
					 | 
				
			||||||
    DisableBasicIRQ: Volatile<u32>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Pending interrupts
 | 
					 | 
				
			||||||
pub struct PendingInterrupts(u64);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Iterator for PendingInterrupts {
 | 
					 | 
				
			||||||
    type Item = usize;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[inline]
 | 
					 | 
				
			||||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
					 | 
				
			||||||
        let int = self.0.trailing_zeros();
 | 
					 | 
				
			||||||
        if int < 64 {
 | 
					 | 
				
			||||||
            self.0 &= !(1 << int);
 | 
					 | 
				
			||||||
            Some(int as usize)
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            None
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// An interrupt controller. Used to enable and disable interrupts as well as to
 | 
					 | 
				
			||||||
/// check if an interrupt is pending.
 | 
					 | 
				
			||||||
pub struct Controller {
 | 
					 | 
				
			||||||
    registers: &'static mut Registers,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Controller {
 | 
					 | 
				
			||||||
    /// Returns a new handle to the interrupt controller.
 | 
					 | 
				
			||||||
    #[inline]
 | 
					 | 
				
			||||||
    pub fn new() -> Controller {
 | 
					 | 
				
			||||||
        Controller {
 | 
					 | 
				
			||||||
            registers: unsafe { &mut *(INT_BASE as *mut Registers) },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Enables the interrupt `int`.
 | 
					 | 
				
			||||||
    pub fn enable(&mut self, int: Interrupt) {
 | 
					 | 
				
			||||||
        self.registers.EnableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Disables the interrupt `int`.
 | 
					 | 
				
			||||||
    pub fn disable(&mut self, int: Interrupt) {
 | 
					 | 
				
			||||||
        self.registers.DisableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Returns `true` if `int` is pending. Otherwise, returns `false`.
 | 
					 | 
				
			||||||
    pub fn is_pending(&self, int: Interrupt) -> bool {
 | 
					 | 
				
			||||||
        self.registers.IRQPending[int as usize / 32].read() & (1 << (int as usize) % 32) != 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Return all pending interrupts.
 | 
					 | 
				
			||||||
    pub fn pending_interrupts(&self) -> PendingInterrupts {
 | 
					 | 
				
			||||||
        let irq1 = self.registers.IRQPending[0].read() as u64;
 | 
					 | 
				
			||||||
        let irq2 = self.registers.IRQPending[1].read() as u64;
 | 
					 | 
				
			||||||
        PendingInterrupts((irq2 << 32) | irq1)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,12 +0,0 @@
 | 
				
			|||||||
#![no_std]
 | 
					 | 
				
			||||||
#![feature(asm)]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern crate volatile;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub mod gpio;
 | 
					 | 
				
			||||||
pub mod timer;
 | 
					 | 
				
			||||||
pub mod mailbox;
 | 
					 | 
				
			||||||
pub mod mini_uart;
 | 
					 | 
				
			||||||
pub mod interrupt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const IO_BASE: usize = 0x3F000000;
 | 
					 | 
				
			||||||
@ -1,80 +0,0 @@
 | 
				
			|||||||
use crate::IO_BASE;
 | 
					 | 
				
			||||||
use volatile::{ReadOnly, Volatile, WriteOnly};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The base address for the `MU` registers.
 | 
					 | 
				
			||||||
const MAILBOX_BASE: usize = IO_BASE + 0xB000 + 0x880;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Available mailbox channels
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// (ref: https://github.com/raspberrypi/firmware/wiki/Mailboxes)
 | 
					 | 
				
			||||||
#[repr(u8)]
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Debug)]
 | 
					 | 
				
			||||||
pub enum MailboxChannel {
 | 
					 | 
				
			||||||
    Framebuffer = 1,
 | 
					 | 
				
			||||||
    Property = 8,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Read from mailbox status register (MAILx_STA).
 | 
					 | 
				
			||||||
#[repr(u32)]
 | 
					 | 
				
			||||||
enum MailboxStatus {
 | 
					 | 
				
			||||||
    MailboxEmpty = 1 << 30,
 | 
					 | 
				
			||||||
    MailboxFull = 1 << 31,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Mailbox registers. We basically only support mailbox 0 & 1. We
 | 
					 | 
				
			||||||
/// deliver to the VC in mailbox 1, it delivers to us in mailbox 0. See
 | 
					 | 
				
			||||||
/// BCM2835-ARM-Peripherals.pdf section 1.3 for an explanation about
 | 
					 | 
				
			||||||
/// the placement of memory barriers.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// (ref: https://github.com/raspberrypi/firmware/wiki/Mailboxes)
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[allow(non_snake_case)]
 | 
					 | 
				
			||||||
struct Registers {
 | 
					 | 
				
			||||||
    MAIL0_RD: ReadOnly<u32>, // 0x00
 | 
					 | 
				
			||||||
    __reserved0: [u32; 3],
 | 
					 | 
				
			||||||
    MAIL0_POL: ReadOnly<u32>, // 0x10
 | 
					 | 
				
			||||||
    MAIL0_SND: ReadOnly<u32>, // 0x14
 | 
					 | 
				
			||||||
    MAIL0_STA: ReadOnly<u32>, // 0x18
 | 
					 | 
				
			||||||
    MAIL0_CNF: Volatile<u32>, // 0x1c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    MAIL1_WRT: WriteOnly<u32>, // 0x20
 | 
					 | 
				
			||||||
    __reserved1: [u32; 3],
 | 
					 | 
				
			||||||
    _MAIL1_POL: ReadOnly<u32>, // 0x30
 | 
					 | 
				
			||||||
    _MAIL1_SND: ReadOnly<u32>, // 0x34
 | 
					 | 
				
			||||||
    MAIL1_STA: ReadOnly<u32>,  // 0x38
 | 
					 | 
				
			||||||
    _MAIL1_CNF: Volatile<u32>, // 0x3c
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The Raspberry Pi's mailbox.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// (ref: https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes)
 | 
					 | 
				
			||||||
pub struct Mailbox {
 | 
					 | 
				
			||||||
    registers: &'static mut Registers,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Mailbox {
 | 
					 | 
				
			||||||
    /// Returns a new instance of `Mailbox`.
 | 
					 | 
				
			||||||
    #[inline]
 | 
					 | 
				
			||||||
    pub fn new() -> Mailbox {
 | 
					 | 
				
			||||||
        Mailbox {
 | 
					 | 
				
			||||||
            registers: unsafe { &mut *(MAILBOX_BASE as *mut Registers) },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Read from the requested channel of mailbox 0.
 | 
					 | 
				
			||||||
    pub fn read(&self, channel: MailboxChannel) -> u32 {
 | 
					 | 
				
			||||||
        loop {
 | 
					 | 
				
			||||||
            while self.registers.MAIL0_STA.read() & (MailboxStatus::MailboxEmpty as u32) != 0 {}
 | 
					 | 
				
			||||||
            let data = self.registers.MAIL0_RD.read();
 | 
					 | 
				
			||||||
            if data & 0xF == channel as u32 {
 | 
					 | 
				
			||||||
                return data & !0xF;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Write to the requested channel of mailbox 1.
 | 
					 | 
				
			||||||
    pub fn write(&mut self, channel: MailboxChannel, data: u32) {
 | 
					 | 
				
			||||||
        while self.registers.MAIL1_STA.read() & (MailboxStatus::MailboxFull as u32) != 0 {}
 | 
					 | 
				
			||||||
        self.registers.MAIL1_WRT.write((data & !0xF) | (channel as u32));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,133 +0,0 @@
 | 
				
			|||||||
use crate::IO_BASE;
 | 
					 | 
				
			||||||
use crate::gpio::{Function, Gpio};
 | 
					 | 
				
			||||||
use volatile::{ReadOnly, Volatile};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The `AUXENB` register from page 9 of the BCM2837 documentation.
 | 
					 | 
				
			||||||
const AUX_ENABLES: *mut Volatile<u8> = (IO_BASE + 0x215004) as *mut Volatile<u8>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The base address for the `MU` registers.
 | 
					 | 
				
			||||||
const MU_REG_BASE: usize = IO_BASE + 0x215040;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Enum representing bit fields of the `AUX_MU_IIR_REG` register.
 | 
					 | 
				
			||||||
#[repr(u8)]
 | 
					 | 
				
			||||||
pub enum MiniUartInterruptId {
 | 
					 | 
				
			||||||
    Transmit = 0b010,
 | 
					 | 
				
			||||||
    Recive = 0b100,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Enum representing bit fields of the `AUX_MU_LSR_REG` register.
 | 
					 | 
				
			||||||
#[repr(u8)]
 | 
					 | 
				
			||||||
enum LsrStatus {
 | 
					 | 
				
			||||||
    DataReady = 1,
 | 
					 | 
				
			||||||
    TxAvailable = 1 << 5,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// MU registers starting from `MU_REG_BASE` (ref: peripherals 2.1, page 8)
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[allow(non_snake_case)]
 | 
					 | 
				
			||||||
struct Registers {
 | 
					 | 
				
			||||||
    AUX_MU_IO_REG: Volatile<u8>,
 | 
					 | 
				
			||||||
    __r0: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_IER_REG: Volatile<u8>,
 | 
					 | 
				
			||||||
    __r1: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_IIR_REG: Volatile<u8>,
 | 
					 | 
				
			||||||
    __r2: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_LCR_REG: Volatile<u8>,
 | 
					 | 
				
			||||||
    __r3: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_MCR_REG: Volatile<u8>,
 | 
					 | 
				
			||||||
    __r4: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_LSR_REG: ReadOnly<u8>,
 | 
					 | 
				
			||||||
    __r5: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_MSR_REG: ReadOnly<u8>,
 | 
					 | 
				
			||||||
    __r6: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_SCRATCH: Volatile<u8>,
 | 
					 | 
				
			||||||
    __r7: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_CNTL_REG: Volatile<u8>,
 | 
					 | 
				
			||||||
    __r8: [u8; 3],
 | 
					 | 
				
			||||||
    AUX_MU_STAT_REG: ReadOnly<u32>,
 | 
					 | 
				
			||||||
    AUX_MU_BAUD_REG: Volatile<u16>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The Raspberry Pi's "mini UART".
 | 
					 | 
				
			||||||
pub struct MiniUart {
 | 
					 | 
				
			||||||
    registers: &'static mut Registers,
 | 
					 | 
				
			||||||
    timeout: Option<u32>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl MiniUart {
 | 
					 | 
				
			||||||
    /// Returns a new instance of `MiniUart`.
 | 
					 | 
				
			||||||
    #[inline]
 | 
					 | 
				
			||||||
    pub fn new() -> MiniUart {
 | 
					 | 
				
			||||||
        let registers = unsafe { &mut *(MU_REG_BASE as *mut Registers) };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        MiniUart {
 | 
					 | 
				
			||||||
            registers: registers,
 | 
					 | 
				
			||||||
            timeout: None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Initializes the mini UART by enabling it as an auxiliary peripheral,
 | 
					 | 
				
			||||||
    /// setting the data size to 8 bits, setting the BAUD rate to ~115200 (baud
 | 
					 | 
				
			||||||
    /// divider of 270), setting GPIO pins 14 and 15 to alternative function 5
 | 
					 | 
				
			||||||
    /// (TXD1/RDXD1), and finally enabling the UART transmitter and receiver.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// By default, reads will never time out. To set a read timeout, use
 | 
					 | 
				
			||||||
    /// `set_read_timeout()`.
 | 
					 | 
				
			||||||
    pub fn init(&mut self) {
 | 
					 | 
				
			||||||
        // Enable the mini UART as an auxiliary device.
 | 
					 | 
				
			||||||
        unsafe { (*AUX_ENABLES).write(1) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Gpio::new(14).into_alt(Function::Alt5).set_gpio_pd(0);
 | 
					 | 
				
			||||||
        Gpio::new(15).into_alt(Function::Alt5).set_gpio_pd(0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_CNTL_REG.write(0); // Disable auto flow control and disable receiver and transmitter (for now)
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_IER_REG.write(1); // Enable receive interrupts and disable transmit interrupts
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_LCR_REG.write(3); // Enable 8 bit mode
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_MCR_REG.write(0); // Set RTS line to be always high
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_BAUD_REG.write(270); // Set baud rate to 115200
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_CNTL_REG.write(3); // Finally, enable transmitter and receiver
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Set the read timeout to `milliseconds` milliseconds.
 | 
					 | 
				
			||||||
    pub fn set_read_timeout(&mut self, milliseconds: u32) {
 | 
					 | 
				
			||||||
        self.timeout = Some(milliseconds)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Write the byte `byte`. This method blocks until there is space available
 | 
					 | 
				
			||||||
    /// in the output FIFO.
 | 
					 | 
				
			||||||
    pub fn write_byte(&mut self, byte: u8) {
 | 
					 | 
				
			||||||
        while self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::TxAvailable as u8) == 0 {}
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_IO_REG.write(byte);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Returns `true` if there is at least one byte ready to be read. If this
 | 
					 | 
				
			||||||
    /// method returns `true`, a subsequent call to `read_byte` is guaranteed to
 | 
					 | 
				
			||||||
    /// return immediately. This method does not block.
 | 
					 | 
				
			||||||
    pub fn has_byte(&self) -> bool {
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::DataReady as u8) != 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Blocks until there is a byte ready to read. If a read timeout is set,
 | 
					 | 
				
			||||||
    /// this method blocks for at most that amount of time. Otherwise, this
 | 
					 | 
				
			||||||
    /// method blocks indefinitely until there is a byte to read.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// Returns `Ok(())` if a byte is ready to read. Returns `Err(())` if the
 | 
					 | 
				
			||||||
    /// timeout expired while waiting for a byte to be ready. If this method
 | 
					 | 
				
			||||||
    /// returns `Ok(())`, a subsequent call to `read_byte` is guaranteed to
 | 
					 | 
				
			||||||
    /// return immediately.
 | 
					 | 
				
			||||||
    pub fn wait_for_byte(&self) -> Result<(), ()> {
 | 
					 | 
				
			||||||
        unimplemented!()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Reads a byte. Blocks indefinitely until a byte is ready to be read.
 | 
					 | 
				
			||||||
    pub fn read_byte(&self) -> u8 {
 | 
					 | 
				
			||||||
        while !self.has_byte() {}
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_IO_REG.read()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Read `AUX_MU_IIR_REG` and determine if the interrupt `id` is pending.
 | 
					 | 
				
			||||||
    pub fn interrupt_is_pending(&self, id: MiniUartInterruptId) -> bool {
 | 
					 | 
				
			||||||
        self.registers.AUX_MU_IIR_REG.read() & 0b110 == id as u8
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,76 +0,0 @@
 | 
				
			|||||||
extern crate aarch64;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use super::BasicTimer;
 | 
					 | 
				
			||||||
use aarch64::regs::*;
 | 
					 | 
				
			||||||
use volatile::*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The base address for the ARM generic timer, IRQs, mailboxes
 | 
					 | 
				
			||||||
const GEN_TIMER_REG_BASE: usize = 0x40000000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Core interrupt sources (ref: QA7 4.10, page 16)
 | 
					 | 
				
			||||||
#[repr(u8)]
 | 
					 | 
				
			||||||
#[allow(dead_code)]
 | 
					 | 
				
			||||||
#[allow(non_snake_case)]
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, PartialEq, Debug)]
 | 
					 | 
				
			||||||
enum CoreInterrupt {
 | 
					 | 
				
			||||||
    CNTPSIRQ = 0,
 | 
					 | 
				
			||||||
    CNTPNSIRQ = 1,
 | 
					 | 
				
			||||||
    CNTHPIRQ = 2,
 | 
					 | 
				
			||||||
    CNTVIRQ = 3,
 | 
					 | 
				
			||||||
    Mailbox0 = 4,
 | 
					 | 
				
			||||||
    Mailbox1 = 5,
 | 
					 | 
				
			||||||
    Mailbox2 = 6,
 | 
					 | 
				
			||||||
    Mailbox3 = 7,
 | 
					 | 
				
			||||||
    Gpu = 8,
 | 
					 | 
				
			||||||
    Pmu = 9,
 | 
					 | 
				
			||||||
    AxiOutstanding = 10,
 | 
					 | 
				
			||||||
    LocalTimer = 11,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Timer, IRQs, mailboxes registers (ref: QA7 chapter 4, page 7)
 | 
					 | 
				
			||||||
#[allow(non_snake_case)]
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
struct Registers {
 | 
					 | 
				
			||||||
    CONTROL: Volatile<u32>,
 | 
					 | 
				
			||||||
    _unused1: [Volatile<u32>; 8],
 | 
					 | 
				
			||||||
    LOCAL_IRQ: Volatile<u32>,
 | 
					 | 
				
			||||||
    _unused2: [Volatile<u32>; 3],
 | 
					 | 
				
			||||||
    LOCAL_TIMER_CTL: Volatile<u32>,
 | 
					 | 
				
			||||||
    LOCAL_TIMER_FLAGS: Volatile<u32>,
 | 
					 | 
				
			||||||
    _unused3: Volatile<u32>,
 | 
					 | 
				
			||||||
    CORE_TIMER_IRQCNTL: [Volatile<u32>; 4],
 | 
					 | 
				
			||||||
    CORE_MAILBOX_IRQCNTL: [Volatile<u32>; 4],
 | 
					 | 
				
			||||||
    CORE_IRQ_SRC: [Volatile<u32>; 4],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The ARM generic timer.
 | 
					 | 
				
			||||||
pub struct GenericTimer {
 | 
					 | 
				
			||||||
    registers: &'static mut Registers,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl BasicTimer for GenericTimer {
 | 
					 | 
				
			||||||
    fn new() -> Self {
 | 
					 | 
				
			||||||
        GenericTimer {
 | 
					 | 
				
			||||||
            registers: unsafe { &mut *(GEN_TIMER_REG_BASE as *mut Registers) },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn init(&mut self) {
 | 
					 | 
				
			||||||
        self.registers.CORE_TIMER_IRQCNTL[0].write(1 << (CoreInterrupt::CNTPNSIRQ as u8));
 | 
					 | 
				
			||||||
        CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn read(&self) -> u64 {
 | 
					 | 
				
			||||||
        let cntfrq = CNTFRQ_EL0.get(); // 62500000
 | 
					 | 
				
			||||||
        (CNTPCT_EL0.get() * 1000000 / (cntfrq as u64)) as u64
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn tick_in(&mut self, us: u32) {
 | 
					 | 
				
			||||||
        let cntfrq = CNTFRQ_EL0.get(); // 62500000
 | 
					 | 
				
			||||||
        CNTP_TVAL_EL0.set(((cntfrq as f64) * (us as f64) / 1000000.0) as u32);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn is_pending(&self) -> bool {
 | 
					 | 
				
			||||||
        self.registers.CORE_IRQ_SRC[0].read() & (1 << (CoreInterrupt::CNTPNSIRQ as u8)) != 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,38 +0,0 @@
 | 
				
			|||||||
#[cfg(feature = "use_generic_timer")]
 | 
					 | 
				
			||||||
mod generic_timer;
 | 
					 | 
				
			||||||
#[cfg(feature = "use_generic_timer")]
 | 
					 | 
				
			||||||
pub use self::generic_timer::GenericTimer as Timer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(not(feature = "use_generic_timer"))]
 | 
					 | 
				
			||||||
mod system_timer;
 | 
					 | 
				
			||||||
#[cfg(not(feature = "use_generic_timer"))]
 | 
					 | 
				
			||||||
pub use self::system_timer::SystemTimer as Timer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The Raspberry Pi timer.
 | 
					 | 
				
			||||||
pub trait BasicTimer {
 | 
					 | 
				
			||||||
    /// Returns a new instance.
 | 
					 | 
				
			||||||
    fn new() -> Self;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Initialization timer.
 | 
					 | 
				
			||||||
    fn init(&mut self);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Reads the timer's counter and returns the 64-bit counter value.
 | 
					 | 
				
			||||||
    /// The returned value is the number of elapsed microseconds.
 | 
					 | 
				
			||||||
    fn read(&self) -> u64;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Sets up a match in timer 1 to occur `us` microseconds from now. If
 | 
					 | 
				
			||||||
    /// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
 | 
					 | 
				
			||||||
    /// interrupt will be issued in `us` microseconds.
 | 
					 | 
				
			||||||
    fn tick_in(&mut self, us: u32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Returns `true` if timer interruption is pending. Otherwise, returns `false`.
 | 
					 | 
				
			||||||
    fn is_pending(&self) -> bool;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// wait for `cycle` CPU cycles
 | 
					 | 
				
			||||||
#[inline(always)]
 | 
					 | 
				
			||||||
pub fn delay(cycle: u32) {
 | 
					 | 
				
			||||||
    for _ in 0..cycle {
 | 
					 | 
				
			||||||
        unsafe { asm!("nop") }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,62 +0,0 @@
 | 
				
			|||||||
use super::BasicTimer;
 | 
					 | 
				
			||||||
use crate::interrupt::{Controller, Interrupt};
 | 
					 | 
				
			||||||
use crate::IO_BASE;
 | 
					 | 
				
			||||||
use volatile::{ReadOnly, Volatile};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The base address for the ARM system timer registers.
 | 
					 | 
				
			||||||
const TIMER_REG_BASE: usize = IO_BASE + 0x3000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// System timer registers (ref: peripherals 12.1, page 172)
 | 
					 | 
				
			||||||
#[repr(C)]
 | 
					 | 
				
			||||||
#[allow(non_snake_case)]
 | 
					 | 
				
			||||||
struct Registers {
 | 
					 | 
				
			||||||
    CS: Volatile<u32>,
 | 
					 | 
				
			||||||
    CLO: ReadOnly<u32>,
 | 
					 | 
				
			||||||
    CHI: ReadOnly<u32>,
 | 
					 | 
				
			||||||
    COMPARE: [Volatile<u32>; 4],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[repr(u8)]
 | 
					 | 
				
			||||||
#[allow(dead_code)]
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, PartialEq, Debug)]
 | 
					 | 
				
			||||||
enum SystemTimerId {
 | 
					 | 
				
			||||||
    Timer0 = 0,
 | 
					 | 
				
			||||||
    Timer1 = 1,
 | 
					 | 
				
			||||||
    Timer2 = 2,
 | 
					 | 
				
			||||||
    Timer3 = 3,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The Raspberry Pi ARM system timer.
 | 
					 | 
				
			||||||
pub struct SystemTimer {
 | 
					 | 
				
			||||||
    registers: &'static mut Registers,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl BasicTimer for SystemTimer {
 | 
					 | 
				
			||||||
    fn new() -> Self {
 | 
					 | 
				
			||||||
        SystemTimer {
 | 
					 | 
				
			||||||
            registers: unsafe { &mut *(TIMER_REG_BASE as *mut Registers) },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn init(&mut self) {
 | 
					 | 
				
			||||||
        Controller::new().enable(Interrupt::Timer1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn read(&self) -> u64 {
 | 
					 | 
				
			||||||
        let low = self.registers.CLO.read();
 | 
					 | 
				
			||||||
        let high = self.registers.CHI.read();
 | 
					 | 
				
			||||||
        ((high as u64) << 32) | (low as u64)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn tick_in(&mut self, us: u32) {
 | 
					 | 
				
			||||||
        let current_low = self.registers.CLO.read();
 | 
					 | 
				
			||||||
        let compare = current_low.wrapping_add(us);
 | 
					 | 
				
			||||||
        self.registers.COMPARE[SystemTimerId::Timer1 as usize].write(compare);
 | 
					 | 
				
			||||||
        self.registers.CS.write(1 << (SystemTimerId::Timer1 as usize)); // unmask
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn is_pending(&self) -> bool {
 | 
					 | 
				
			||||||
        let controller = Controller::new();
 | 
					 | 
				
			||||||
        controller.is_pending(Interrupt::Timer1)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					.section .text.entry
 | 
				
			||||||
 | 
					.globl _start
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_start:
 | 
				
			||||||
 | 
					    ldr     x0, =bootstacktop
 | 
				
			||||||
 | 
					    mov     sp, x0
 | 
				
			||||||
 | 
					    bl      rust_main
 | 
				
			||||||
 | 
					1:  b       1b
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
pub const RECURSIVE_INDEX: usize = 0o777;
 | 
					pub const RECURSIVE_INDEX: usize = 0o777;
 | 
				
			||||||
pub const KERNEL_OFFSET: usize = 0;
 | 
					pub const KERNEL_OFFSET: usize = 0xFFFF_0000_0000_0000;
 | 
				
			||||||
pub const KERNEL_PML4: usize = 0;
 | 
					pub const KERNEL_PML4: usize = 0;
 | 
				
			||||||
pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024;
 | 
					pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024;
 | 
				
			||||||
pub const MEMORY_OFFSET: usize = 0;
 | 
					pub const MEMORY_OFFSET: usize = 0;
 | 
				
			||||||
pub const USER_STACK_OFFSET: usize = 0xffff_8000_0000_0000;
 | 
					pub const USER_STACK_OFFSET: usize = 0x0000_8000_0000_0000 - USER_STACK_SIZE;
 | 
				
			||||||
pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024;
 | 
					pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024;
 | 
				
			||||||
pub const USER32_STACK_OFFSET: usize = USER_STACK_OFFSET;
 | 
					pub const USER32_STACK_OFFSET: usize = USER_STACK_OFFSET;
 | 
				
			||||||
 | 
				
			|||||||
					Loading…
					
					
				
		Reference in new issue