Merge branch 'msi' into 'master'
Greatly improve xhcid by using real MSI-X irqs. See merge request redox-os/drivers!59
This commit is contained in:
Generated
+292
-99
@@ -47,8 +47,8 @@ name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -84,6 +84,15 @@ dependencies = [
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
@@ -132,6 +141,25 @@ name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chashmap"
|
||||
version = "2.2.2"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/chashmap.git#da92c702e052cde00db5e409dfb234af71928152"
|
||||
dependencies = [
|
||||
"owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
@@ -164,10 +192,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -188,8 +217,8 @@ dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -203,10 +232,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.0"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -250,6 +279,88 @@ name = "futures"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpt"
|
||||
version = "0.6.3"
|
||||
@@ -263,10 +374,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.6"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -328,7 +439,7 @@ name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -367,7 +478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.66"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -380,10 +491,19 @@ name = "lock_api"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
@@ -410,12 +530,17 @@ name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -435,7 +560,7 @@ dependencies = [
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -454,7 +579,7 @@ dependencies = [
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -468,7 +593,7 @@ version = "0.6.7"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999"
|
||||
dependencies = [
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)",
|
||||
]
|
||||
|
||||
@@ -489,7 +614,7 @@ version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -502,7 +627,7 @@ dependencies = [
|
||||
"extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)",
|
||||
"hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)",
|
||||
"ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)",
|
||||
"pbr 1.0.2 (git+https://github.com/a8m/pb)",
|
||||
@@ -522,7 +647,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-uni
|
||||
dependencies = [
|
||||
"arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)",
|
||||
"extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)",
|
||||
"pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -589,8 +714,8 @@ name = "num_cpus"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -620,7 +745,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -635,18 +760,42 @@ dependencies = [
|
||||
"parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "partitionlib"
|
||||
version = "0.1.0"
|
||||
@@ -662,8 +811,8 @@ name = "pbr"
|
||||
version = "1.0.2"
|
||||
source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966"
|
||||
dependencies = [
|
||||
"crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -674,7 +823,7 @@ name = "pbr"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -684,12 +833,15 @@ dependencies = [
|
||||
name = "pcid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -704,14 +856,29 @@ name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.8"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -729,10 +896,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -741,7 +908,7 @@ version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -796,7 +963,7 @@ name = "rand_jitter"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -808,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (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.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -848,6 +1015,16 @@ dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-log"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#08693d48b2d7b56fcb07a1e62e257bacce749cef"
|
||||
dependencies = [
|
||||
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_event"
|
||||
version = "0.1.0"
|
||||
@@ -884,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -931,7 +1108,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -946,7 +1123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -962,9 +1139,9 @@ name = "scroll_derive"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -983,7 +1160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -995,7 +1172,7 @@ version = "0.32.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1013,30 +1190,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.104"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.104"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.47"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1057,7 +1234,7 @@ name = "smallvec"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1093,11 +1270,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.14"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1106,7 +1283,7 @@ name = "termion"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1122,20 +1299,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.10"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.10"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1143,7 +1320,7 @@ name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1294,7 +1471,7 @@ dependencies = [
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)",
|
||||
"mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)",
|
||||
@@ -1303,20 +1480,12 @@ dependencies = [
|
||||
"tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1403,7 +1572,7 @@ dependencies = [
|
||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
|
||||
"thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xhcid 0.1.0",
|
||||
]
|
||||
|
||||
@@ -1523,15 +1692,20 @@ name = "xhcid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)",
|
||||
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pcid 0.1.0",
|
||||
"plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)",
|
||||
"redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)",
|
||||
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1544,6 +1718,7 @@ dependencies = [
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
||||
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
|
||||
@@ -1552,21 +1727,32 @@ dependencies = [
|
||||
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
|
||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "<none>"
|
||||
"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
|
||||
"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
|
||||
"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
||||
"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
|
||||
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
|
||||
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
|
||||
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "<none>"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
|
||||
"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780"
|
||||
"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
|
||||
"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
|
||||
"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba"
|
||||
"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
|
||||
"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7"
|
||||
"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
|
||||
"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
|
||||
"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
|
||||
"checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "<none>"
|
||||
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||
"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
|
||||
"checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273"
|
||||
"checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7"
|
||||
@@ -1576,14 +1762,16 @@ dependencies = [
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
||||
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
|
||||
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
|
||||
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
|
||||
"checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "<none>"
|
||||
"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
|
||||
@@ -1601,16 +1789,21 @@ dependencies = [
|
||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
"checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402"
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
|
||||
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
||||
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
|
||||
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
|
||||
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
|
||||
"checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "<none>"
|
||||
"checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "<none>"
|
||||
"checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||
"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
|
||||
"checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
|
||||
"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
@@ -1623,6 +1816,7 @@ dependencies = [
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)" = "<none>"
|
||||
"checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "<none>"
|
||||
"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "<none>"
|
||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
@@ -1631,10 +1825,10 @@ dependencies = [
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b"
|
||||
"checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76"
|
||||
"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
||||
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
"checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1"
|
||||
"checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28"
|
||||
"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a"
|
||||
@@ -1642,9 +1836,9 @@ dependencies = [
|
||||
"checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||
"checksum serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90"
|
||||
"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
|
||||
"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
|
||||
"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
|
||||
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
|
||||
@@ -1653,11 +1847,11 @@ dependencies = [
|
||||
"checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d"
|
||||
"checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
|
||||
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad"
|
||||
"checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7"
|
||||
"checksum thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f0570dc61221295909abdb95c739f2e74325e14293b2026b0a7e195091ec54ae"
|
||||
"checksum thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "227362df41d566be41a28f64401e07a043157c21c14b9785a0d8e256f940a8fd"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
|
||||
"checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
|
||||
@@ -1671,7 +1865,6 @@ dependencies = [
|
||||
"checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
|
||||
"checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
|
||||
"checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
|
||||
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
|
||||
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use orbclient;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::str;
|
||||
|
||||
+3
-1
@@ -22,7 +22,7 @@ vendor = 33006
|
||||
device = 48879
|
||||
command = ["bgad", "$NAME", "$BAR0"]
|
||||
|
||||
#nvmed
|
||||
# nvmed
|
||||
[[drivers]]
|
||||
name = "NVME storage"
|
||||
class = 1
|
||||
@@ -37,9 +37,11 @@ vendor = 33006
|
||||
device = 51966
|
||||
command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"]
|
||||
|
||||
# xhcid
|
||||
[[drivers]]
|
||||
name = "XHCI"
|
||||
class = 12
|
||||
subclass = 3
|
||||
interface = 48
|
||||
command = ["xhcid", "$NAME", "$BAR0", "$IRQ"]
|
||||
channel_name = "pcid-xhcid"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/target
|
||||
+16
-5
@@ -3,10 +3,21 @@ name = "pcid"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[[bin]]
|
||||
name = "pcid"
|
||||
path = "src/main.rs"
|
||||
|
||||
[lib]
|
||||
name = "pcid_interface"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
bincode = "1.2"
|
||||
bitflags = "1"
|
||||
byteorder = "1.2"
|
||||
redox_syscall = "0.1"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
toml = "0.4"
|
||||
libc = "0.2"
|
||||
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
thiserror = "1"
|
||||
toml = "0.5"
|
||||
|
||||
+7
-4
@@ -1,12 +1,14 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::Range;
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct Config {
|
||||
pub drivers: Vec<DriverConfig>
|
||||
pub drivers: Vec<DriverConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct DriverConfig {
|
||||
pub name: Option<String>,
|
||||
pub class: Option<u8>,
|
||||
@@ -16,5 +18,6 @@ pub struct DriverConfig {
|
||||
pub vendor: Option<u16>,
|
||||
pub device: Option<u16>,
|
||||
pub device_id_range: Option<Range<u16>>,
|
||||
pub command: Option<Vec<String>>
|
||||
pub command: Option<Vec<String>>,
|
||||
pub channel_name: Option<String>,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::prelude::*;
|
||||
use std::{env, io};
|
||||
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
|
||||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||
use thiserror::Error;
|
||||
|
||||
pub use crate::pci::PciBar;
|
||||
pub use crate::pci::msi;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
#[repr(u8)]
|
||||
pub enum LegacyInterruptPin {
|
||||
/// INTa#
|
||||
IntA = 1,
|
||||
/// INTb#
|
||||
IntB = 2,
|
||||
/// INTc#
|
||||
IntC = 3,
|
||||
/// INTd#
|
||||
IntD = 4,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct PciFunction {
|
||||
/// Number of PCI bus
|
||||
pub bus_num: u8,
|
||||
|
||||
/// Number of PCI device
|
||||
pub dev_num: u8,
|
||||
|
||||
/// Number of PCI function
|
||||
pub func_num: u8,
|
||||
|
||||
/// PCI Base Address Registers
|
||||
pub bars: [PciBar; 6],
|
||||
|
||||
/// BAR sizes
|
||||
pub bar_sizes: [u32; 6],
|
||||
|
||||
/// Legacy IRQ line
|
||||
pub legacy_interrupt_line: u8,
|
||||
|
||||
/// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all.
|
||||
pub legacy_interrupt_pin: Option<LegacyInterruptPin>,
|
||||
|
||||
/// Vendor ID
|
||||
pub venid: u16,
|
||||
/// Device ID
|
||||
pub devid: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SubdriverArguments {
|
||||
pub func: PciFunction,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum FeatureStatus {
|
||||
Enabled,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
impl FeatureStatus {
|
||||
pub fn enabled(enabled: bool) -> Self {
|
||||
if enabled {
|
||||
Self::Enabled
|
||||
} else {
|
||||
Self::Disabled
|
||||
}
|
||||
}
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
if let &Self::Enabled = self { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PciFeature {
|
||||
Msi,
|
||||
MsiX,
|
||||
}
|
||||
impl PciFeature {
|
||||
pub fn is_msi(&self) -> bool {
|
||||
if let &Self::Msi = self { true } else { false }
|
||||
}
|
||||
pub fn is_msix(&self) -> bool {
|
||||
if let &Self::MsiX = self { true } else { false }
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum PciFeatureInfo {
|
||||
Msi(msi::MsiCapability),
|
||||
MsiX(msi::MsixCapability),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PcidClientHandleError {
|
||||
#[error("i/o error: {0}")]
|
||||
IoError(#[from] io::Error),
|
||||
|
||||
#[error("JSON ser/de error: {0}")]
|
||||
SerializationError(#[from] bincode::Error),
|
||||
|
||||
#[error("environment variable error: {0}")]
|
||||
EnvError(#[from] env::VarError),
|
||||
|
||||
#[error("malformed fd: {0}")]
|
||||
EnvValidityError(std::num::ParseIntError),
|
||||
|
||||
#[error("invalid response: {0:?}")]
|
||||
InvalidResponse(PcidClientResponse),
|
||||
}
|
||||
pub type Result<T, E = PcidClientHandleError> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum PcidClientRequest {
|
||||
RequestConfig,
|
||||
RequestFeatures,
|
||||
EnableFeature(PciFeature),
|
||||
FeatureStatus(PciFeature),
|
||||
FeatureInfo(PciFeature),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum PcidServerResponseError {
|
||||
NonexistentFeature(PciFeature),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum PcidClientResponse {
|
||||
Config(SubdriverArguments),
|
||||
AllFeatures(Vec<(PciFeature, FeatureStatus)>),
|
||||
FeatureEnabled(PciFeature),
|
||||
FeatureStatus(PciFeature, FeatureStatus),
|
||||
Error(PcidServerResponseError),
|
||||
FeatureInfo(PciFeature, PciFeatureInfo),
|
||||
}
|
||||
|
||||
// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over
|
||||
// a channel, the communication could potentially be done via mmap, using a channel
|
||||
// very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields
|
||||
// are stored in the same buffer as the actual data).
|
||||
/// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`.
|
||||
pub struct PcidServerHandle {
|
||||
pcid_to_client: File,
|
||||
pcid_from_client: File,
|
||||
}
|
||||
|
||||
pub(crate) fn send<W: Write, T: Serialize>(w: &mut W, message: &T) -> Result<()> {
|
||||
let mut data = Vec::new();
|
||||
bincode::serialize_into(&mut data, message)?;
|
||||
let length_bytes = u64::to_le_bytes(data.len() as u64);
|
||||
w.write_all(&length_bytes)?;
|
||||
w.write_all(&data)?;
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) fn recv<R: Read, T: DeserializeOwned>(r: &mut R) -> Result<T> {
|
||||
let mut length_bytes = [0u8; 8];
|
||||
r.read_exact(&mut length_bytes)?;
|
||||
let length = u64::from_le_bytes(length_bytes);
|
||||
if length > 0x100_000 {
|
||||
panic!("pcid_interface: buffer too large");
|
||||
}
|
||||
let mut data = vec! [0u8; length as usize];
|
||||
r.read_exact(&mut data)?;
|
||||
|
||||
Ok(bincode::deserialize_from(&data[..])?)
|
||||
}
|
||||
|
||||
impl PcidServerHandle {
|
||||
pub fn connect(pcid_to_client: RawFd, pcid_from_client: RawFd) -> Result<Self> {
|
||||
Ok(Self {
|
||||
pcid_to_client: unsafe { File::from_raw_fd(pcid_to_client) },
|
||||
pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client) },
|
||||
})
|
||||
}
|
||||
pub fn connect_default() -> Result<Self> {
|
||||
let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::<RawFd>().map_err(PcidClientHandleError::EnvValidityError)?;
|
||||
let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::<RawFd>().map_err(PcidClientHandleError::EnvValidityError)?;
|
||||
|
||||
Self::connect(pcid_to_client_fd, pcid_from_client_fd)
|
||||
}
|
||||
pub(crate) fn send(&mut self, req: &PcidClientRequest) -> Result<()> {
|
||||
send(&mut self.pcid_from_client, req)
|
||||
}
|
||||
pub(crate) fn recv(&mut self) -> Result<PcidClientResponse> {
|
||||
recv(&mut self.pcid_to_client)
|
||||
}
|
||||
pub fn fetch_config(&mut self) -> Result<SubdriverArguments> {
|
||||
self.send(&PcidClientRequest::RequestConfig)?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::Config(a) => Ok(a),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn fetch_all_features(&mut self) -> Result<Vec<(PciFeature, FeatureStatus)>> {
|
||||
self.send(&PcidClientRequest::RequestFeatures)?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::AllFeatures(a) => Ok(a),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn feature_status(&mut self, feature: PciFeature) -> Result<FeatureStatus> {
|
||||
self.send(&PcidClientRequest::FeatureStatus(feature))?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::FeatureStatus(feat, status) if feat == feature => Ok(status),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> {
|
||||
self.send(&PcidClientRequest::EnableFeature(feature))?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::FeatureEnabled(feat) if feat == feature => Ok(()),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn feature_info(&mut self, feature: PciFeature) -> Result<PciFeatureInfo> {
|
||||
self.send(&PcidClientRequest::FeatureInfo(feature))?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::FeatureInfo(feat, info) if feat == feature => Ok(info),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
//! Interface to `pcid`.
|
||||
|
||||
#![feature(asm)]
|
||||
|
||||
mod driver_interface;
|
||||
mod pci;
|
||||
pub use driver_interface::*;
|
||||
+232
-19
@@ -1,37 +1,163 @@
|
||||
#![feature(asm)]
|
||||
|
||||
#[macro_use] extern crate bitflags;
|
||||
extern crate bitflags;
|
||||
extern crate byteorder;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
extern crate syscall;
|
||||
extern crate toml;
|
||||
|
||||
use std::{env, i64};
|
||||
use std::fs::{File, metadata, read_dir};
|
||||
use std::io::Read;
|
||||
use std::io::prelude::*;
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::process::Command;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{env, io, i64, thread};
|
||||
|
||||
use syscall::iopl;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType};
|
||||
use crate::pci::{Pci, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType};
|
||||
use crate::pci::cap::Capability as PciCapability;
|
||||
|
||||
mod config;
|
||||
mod driver_interface;
|
||||
mod pci;
|
||||
|
||||
fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
|
||||
pub struct DriverHandler {
|
||||
config: config::DriverConfig,
|
||||
bus_num: u8,
|
||||
dev_num: u8,
|
||||
func_num: u8,
|
||||
header: PciHeader,
|
||||
capabilities: Vec<(u8, PciCapability)>,
|
||||
|
||||
state: Arc<State>,
|
||||
}
|
||||
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(pci: &Pci, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T {
|
||||
let bus = PciBus {
|
||||
pci,
|
||||
num: bus_num,
|
||||
};
|
||||
let dev = PciDev {
|
||||
bus: &bus,
|
||||
num: dev_num,
|
||||
};
|
||||
let func = PciFunc {
|
||||
dev: &dev,
|
||||
num: func_num,
|
||||
};
|
||||
function(&func)
|
||||
}
|
||||
impl DriverHandler {
|
||||
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(&self, function: F) -> T {
|
||||
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, function)
|
||||
}
|
||||
fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse {
|
||||
use driver_interface::*;
|
||||
use crate::pci::cap::{MsiCapability, MsixCapability};
|
||||
|
||||
match request {
|
||||
PcidClientRequest::RequestConfig => {
|
||||
PcidClientResponse::Config(args.clone())
|
||||
}
|
||||
PcidClientRequest::RequestFeatures => {
|
||||
PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability {
|
||||
PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))),
|
||||
PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))),
|
||||
_ => None,
|
||||
}).collect())
|
||||
}
|
||||
PcidClientRequest::EnableFeature(feature) => match feature {
|
||||
PciFeature::Msi => {
|
||||
let (offset, capability): (u8, &mut MsiCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msi_mut().map(|cap| (offset, cap))) {
|
||||
Some(tuple) => tuple,
|
||||
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
|
||||
};
|
||||
unsafe {
|
||||
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
capability.set_enabled(true);
|
||||
capability.write_message_control(func, offset);
|
||||
});
|
||||
}
|
||||
PcidClientResponse::FeatureEnabled(feature)
|
||||
}
|
||||
PciFeature::MsiX => {
|
||||
let (offset, capability): (u8, &mut MsixCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msix_mut().map(|cap| (offset, cap))) {
|
||||
Some(tuple) => tuple,
|
||||
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
|
||||
};
|
||||
unsafe {
|
||||
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
capability.set_msix_enabled(true);
|
||||
capability.write_a(func, offset);
|
||||
});
|
||||
}
|
||||
PcidClientResponse::FeatureEnabled(feature)
|
||||
}
|
||||
}
|
||||
PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(feature, match feature {
|
||||
PciFeature::Msi => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::Msi(msi) = capability {
|
||||
Some(FeatureStatus::enabled(msi.enabled()))
|
||||
} else {
|
||||
None
|
||||
}).unwrap_or(FeatureStatus::Disabled),
|
||||
PciFeature::MsiX => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::MsiX(msix) = capability {
|
||||
Some(FeatureStatus::enabled(msix.msix_enabled()))
|
||||
} else {
|
||||
None
|
||||
}).unwrap_or(FeatureStatus::Disabled),
|
||||
}),
|
||||
PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature {
|
||||
PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) {
|
||||
PciFeatureInfo::Msi(*info)
|
||||
} else {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
|
||||
}
|
||||
PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) {
|
||||
PciFeatureInfo::MsiX(*info)
|
||||
} else {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
fn handle_spawn(mut self, pcid_to_client_write: Option<usize>, pcid_from_client_read: Option<usize>, args: driver_interface::SubdriverArguments) {
|
||||
use driver_interface::*;
|
||||
|
||||
if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) {
|
||||
let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) };
|
||||
let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) };
|
||||
|
||||
while let Ok(msg) = recv(&mut pcid_from_client) {
|
||||
let response = self.respond(msg, &args);
|
||||
send(&mut pcid_to_client, &response).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
threads: Mutex<Vec<thread::JoinHandle<()>>>,
|
||||
pci: Pci,
|
||||
}
|
||||
|
||||
fn handle_parsed_header(state: Arc<State>, config: &Config, bus_num: u8,
|
||||
dev_num: u8, func_num: u8, header: PciHeader) {
|
||||
let pci = &state.pci;
|
||||
|
||||
let raw_class: u8 = header.class().into();
|
||||
let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}",
|
||||
bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class,
|
||||
header.subclass(), header.interface(), header.revision(), header.class());
|
||||
|
||||
match header.class() {
|
||||
PciClass::Legacy if header.subclass() == 1 => string.push_str(" VGA CTL"),
|
||||
PciClass::Storage => match header.subclass() {
|
||||
0x01 => {
|
||||
string.push_str(" IDE");
|
||||
},
|
||||
0x06 => {
|
||||
string.push_str(" SATA");
|
||||
0x06 => if header.interface() == 0 {
|
||||
string.push_str(" SATA VND");
|
||||
} else if header.interface() == 1 {
|
||||
string.push_str(" SATA AHCI");
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
@@ -130,6 +256,8 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
|
||||
pci.write(bus_num, dev_num, func_num, 0x3C, data);
|
||||
}
|
||||
|
||||
let interrupt_pin = unsafe { pci.read(bus_num, dev_num, func_num, 0x3B) };
|
||||
|
||||
// Find BAR sizes
|
||||
let mut bars = [PciBar::None; 6];
|
||||
let mut bar_sizes = [0; 6];
|
||||
@@ -166,9 +294,54 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: find a better way to pass the header data down to the
|
||||
// device driver, making passing the capabilities list etc
|
||||
// posible.
|
||||
let capabilities = {
|
||||
let bus = PciBus {
|
||||
pci,
|
||||
num: bus_num,
|
||||
};
|
||||
let dev = PciDev {
|
||||
bus: &bus,
|
||||
num: dev_num
|
||||
};
|
||||
let func = PciFunc {
|
||||
dev: &dev,
|
||||
num: func_num,
|
||||
};
|
||||
crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::<Vec<_>>()
|
||||
};
|
||||
println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities);
|
||||
|
||||
use driver_interface::LegacyInterruptPin;
|
||||
|
||||
let legacy_interrupt_pin = match interrupt_pin {
|
||||
0 => None,
|
||||
1 => Some(LegacyInterruptPin::IntA),
|
||||
2 => Some(LegacyInterruptPin::IntB),
|
||||
3 => Some(LegacyInterruptPin::IntC),
|
||||
4 => Some(LegacyInterruptPin::IntD),
|
||||
|
||||
other => {
|
||||
println!("pcid: invalid interrupt pin: {}", other);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let func = driver_interface::PciFunction {
|
||||
bars,
|
||||
bar_sizes,
|
||||
bus_num,
|
||||
dev_num,
|
||||
func_num,
|
||||
devid: header.device_id(),
|
||||
legacy_interrupt_line: irq,
|
||||
legacy_interrupt_pin,
|
||||
venid: header.vendor_id(),
|
||||
};
|
||||
|
||||
let subdriver_args = driver_interface::SubdriverArguments {
|
||||
func,
|
||||
};
|
||||
|
||||
let mut args = args.iter();
|
||||
if let Some(program) = args.next() {
|
||||
let mut command = Command::new(program);
|
||||
@@ -199,11 +372,41 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
|
||||
}
|
||||
|
||||
println!("PCID SPAWN {:?}", command);
|
||||
match command.spawn() {
|
||||
Ok(mut child) => match child.wait() {
|
||||
Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()),
|
||||
Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err)
|
||||
},
|
||||
|
||||
let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.channel_name.is_some() {
|
||||
let mut fds1 = [0usize; 2];
|
||||
let mut fds2 = [0usize; 2];
|
||||
|
||||
syscall::pipe2(&mut fds1, 0).expect("pcid: failed to create pcid->client pipe");
|
||||
syscall::pipe2(&mut fds2, 0).expect("pcid: failed to create client->pcid pipe");
|
||||
|
||||
let [pcid_to_client_read, pcid_to_client_write] = fds1;
|
||||
let [pcid_from_client_read, pcid_from_client_write] = fds2;
|
||||
|
||||
(Some(pcid_to_client_write), Some(pcid_from_client_read), vec! [("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write))])
|
||||
} else {
|
||||
(None, None, vec! [])
|
||||
};
|
||||
|
||||
match command.envs(envs).spawn() {
|
||||
Ok(mut child) => {
|
||||
let driver_handler = DriverHandler {
|
||||
bus_num,
|
||||
dev_num,
|
||||
func_num,
|
||||
config: driver.clone(),
|
||||
header,
|
||||
state: Arc::clone(&state),
|
||||
capabilities,
|
||||
};
|
||||
let thread = thread::spawn(move || {
|
||||
driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args);
|
||||
});
|
||||
match child.wait() {
|
||||
Ok(_status) => (),
|
||||
Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err),
|
||||
}
|
||||
}
|
||||
Err(err) => println!("pcid: failed to execute {:?}: {}", command, err)
|
||||
}
|
||||
}
|
||||
@@ -241,18 +444,24 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let state = Arc::new(State {
|
||||
pci: Pci::new(),
|
||||
threads: Mutex::new(Vec::new()),
|
||||
});
|
||||
|
||||
let pci = &state.pci;
|
||||
|
||||
unsafe { iopl(3).unwrap() };
|
||||
|
||||
print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n");
|
||||
|
||||
let pci = Pci::new();
|
||||
'bus: for bus in pci.buses() {
|
||||
'dev: for dev in bus.devs() {
|
||||
for func in dev.funcs() {
|
||||
let func_num = func.num;
|
||||
match PciHeader::from_reader(func) {
|
||||
Ok(header) => {
|
||||
handle_parsed_header(&config, &pci, bus.num, dev.num, func_num, header);
|
||||
handle_parsed_header(Arc::clone(&state), &config, bus.num, dev.num, func_num, header);
|
||||
}
|
||||
Err(PciHeaderError::NoDevice) => {
|
||||
if func_num == 0 {
|
||||
@@ -272,4 +481,8 @@ fn main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for thread in state.threads.lock().unwrap().drain(..) {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PciBar {
|
||||
None,
|
||||
Memory(u32),
|
||||
|
||||
@@ -13,6 +13,9 @@ impl<'pci> PciBus<'pci> {
|
||||
pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 {
|
||||
self.pci.read(self.num, dev, func, offset)
|
||||
}
|
||||
pub unsafe fn write(&self, dev: u8, func: u8, offset: u8, value: u32) {
|
||||
self.pci.write(self.num, dev, func, offset, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PciBusIter<'pci> {
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
use super::func::ConfigReader;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
pub struct CapabilityOffsetsIter<'a, R> {
|
||||
offset: u8,
|
||||
reader: &'a R,
|
||||
}
|
||||
impl<'a, R> CapabilityOffsetsIter<'a, R> {
|
||||
pub fn new(offset: u8, reader: &'a R) -> Self {
|
||||
Self {
|
||||
offset,
|
||||
reader,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, R> Iterator for CapabilityOffsetsIter<'a, R>
|
||||
where
|
||||
R: ConfigReader
|
||||
{
|
||||
type Item = u8;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
assert_eq!(self.offset & 0xF8, self.offset, "capability must be dword aligned");
|
||||
|
||||
if self.offset == 0 { return None };
|
||||
|
||||
let first_dword = dbg!(self.reader.read_u32(dbg!(self.offset)));
|
||||
let next = ((first_dword >> 8) & 0xFF) as u8;
|
||||
|
||||
let offset = self.offset;
|
||||
self.offset = next;
|
||||
|
||||
Some(offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum CapabilityId {
|
||||
Msi = 0x05,
|
||||
MsiX = 0x11,
|
||||
Pcie = 0x10,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MsiCapability {
|
||||
_32BitAddress {
|
||||
message_control: u32,
|
||||
message_address: u32,
|
||||
message_data: u32,
|
||||
},
|
||||
_64BitAddress {
|
||||
message_control: u32,
|
||||
message_address_lo: u32,
|
||||
message_address_hi: u32,
|
||||
message_data: u32,
|
||||
},
|
||||
_32BitAddressWithPvm {
|
||||
message_control: u32,
|
||||
message_address: u32,
|
||||
message_data: u32,
|
||||
mask_bits: u32,
|
||||
pending_bits: u32,
|
||||
},
|
||||
_64BitAddressWithPvm {
|
||||
message_control: u32,
|
||||
message_address_lo: u32,
|
||||
message_address_hi: u32,
|
||||
message_data: u32,
|
||||
mask_bits: u32,
|
||||
pending_bits: u32,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PcieCapability {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MsixCapability {
|
||||
pub a: u32,
|
||||
pub b: u32,
|
||||
pub c: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Capability {
|
||||
Msi(MsiCapability),
|
||||
MsiX(MsixCapability),
|
||||
Pcie(PcieCapability),
|
||||
Other(u8),
|
||||
}
|
||||
|
||||
impl Capability {
|
||||
pub fn as_msi(&self) -> Option<&MsiCapability> {
|
||||
match self {
|
||||
&Self::Msi(ref msi) => Some(msi),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn as_msix(&self) -> Option<&MsixCapability> {
|
||||
match self {
|
||||
&Self::MsiX(ref msix) => Some(msix),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn as_msi_mut(&mut self) -> Option<&mut MsiCapability> {
|
||||
match self {
|
||||
&mut Self::Msi(ref mut msi) => Some(msi),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn as_msix_mut(&mut self) -> Option<&mut MsixCapability> {
|
||||
match self {
|
||||
&mut Self::MsiX(ref mut msix) => Some(msix),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn into_msi(self) -> Option<MsiCapability> {
|
||||
match self {
|
||||
Self::Msi(msi) => Some(msi),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn into_msix(self) -> Option<MsixCapability> {
|
||||
match self {
|
||||
Self::MsiX(msix) => Some(msix),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
unsafe fn parse_msi<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
Self::Msi(MsiCapability::parse(reader, offset))
|
||||
}
|
||||
unsafe fn parse_msix<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
Self::MsiX(MsixCapability {
|
||||
a: reader.read_u32(offset),
|
||||
b: reader.read_u32(offset + 4),
|
||||
c: reader.read_u32(offset + 8),
|
||||
})
|
||||
}
|
||||
unsafe fn parse_pcie<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
// TODO
|
||||
Self::Pcie(PcieCapability {})
|
||||
}
|
||||
unsafe fn parse<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
assert_eq!(offset & 0xF8, offset, "capability must be dword aligned");
|
||||
|
||||
let dword = reader.read_u32(offset);
|
||||
let capability_id = (dword & 0xFF) as u8;
|
||||
|
||||
if capability_id == CapabilityId::Msi as u8 {
|
||||
Self::parse_msi(reader, offset)
|
||||
} else if capability_id == CapabilityId::MsiX as u8 {
|
||||
Self::parse_msix(reader, offset)
|
||||
} else if capability_id == CapabilityId::Pcie as u8 {
|
||||
Self::parse_pcie(reader, offset)
|
||||
} else {
|
||||
Self::Other(capability_id)
|
||||
//panic!("unimplemented or malformed capability id: {}", capability_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CapabilitiesIter<'a, R> {
|
||||
pub inner: CapabilityOffsetsIter<'a, R>,
|
||||
}
|
||||
|
||||
impl<'a, R> Iterator for CapabilitiesIter<'a, R>
|
||||
where
|
||||
R: ConfigReader
|
||||
{
|
||||
type Item = (u8, Capability);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let offset = self.inner.next()?;
|
||||
Some((offset, unsafe { Capability::parse(self.inner.reader, offset) }))
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,9 @@ impl<'pci> PciDev<'pci> {
|
||||
pub unsafe fn read(&self, func: u8, offset: u8) -> u32 {
|
||||
self.bus.read(self.num, func, offset)
|
||||
}
|
||||
pub unsafe fn write(&self, func: u8, offset: u8, value: u32) {
|
||||
self.bus.write(self.num, func, offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PciDevIter<'pci> {
|
||||
|
||||
+20
-1
@@ -2,6 +2,9 @@ use byteorder::{LittleEndian, ByteOrder};
|
||||
|
||||
use super::PciDev;
|
||||
|
||||
// TODO: PCI Express Configuration Space, which uses a flat memory buffer, rather than IN/OUT
|
||||
// instructions.
|
||||
|
||||
pub trait ConfigReader {
|
||||
unsafe fn read_range(&self, offset: u8, len: u8) -> Vec<u8> {
|
||||
assert!(len > 3 && len % 4 == 0);
|
||||
@@ -17,11 +20,22 @@ pub trait ConfigReader {
|
||||
}
|
||||
|
||||
unsafe fn read_u32(&self, offset: u8) -> u32;
|
||||
|
||||
unsafe fn read_u8(&self, offset: u8) -> u8 {
|
||||
let dword_offset = (offset / 4) * 4;
|
||||
let dword = self.read_u32(dword_offset);
|
||||
|
||||
let shift = (offset % 4) * 8;
|
||||
((dword >> shift) & 0xFF) as u8
|
||||
}
|
||||
}
|
||||
pub trait ConfigWriter {
|
||||
unsafe fn write_u32(&self, offset: u8, value: u32);
|
||||
}
|
||||
|
||||
pub struct PciFunc<'pci> {
|
||||
pub dev: &'pci PciDev<'pci>,
|
||||
pub num: u8
|
||||
pub num: u8,
|
||||
}
|
||||
|
||||
impl<'pci> ConfigReader for PciFunc<'pci> {
|
||||
@@ -29,3 +43,8 @@ impl<'pci> ConfigReader for PciFunc<'pci> {
|
||||
self.dev.read(self.num, offset)
|
||||
}
|
||||
}
|
||||
impl<'pci> ConfigWriter for PciFunc<'pci> {
|
||||
unsafe fn write_u32(&self, offset: u8, value: u32) {
|
||||
self.dev.write(self.num, offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use byteorder::{LittleEndian, ByteOrder};
|
||||
use super::func::ConfigReader;
|
||||
use super::class::PciClass;
|
||||
use super::bar::PciBar;
|
||||
use bitflags::bitflags;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum PciHeaderError {
|
||||
@@ -26,7 +27,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum PciHeader {
|
||||
General {
|
||||
vendor_id: u16,
|
||||
@@ -123,7 +124,6 @@ impl PciHeader {
|
||||
let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]);
|
||||
let subsystem_id = LittleEndian::read_u16(&bytes[30..32]);
|
||||
let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]);
|
||||
// TODO: Parse out the capabilities list.
|
||||
let cap_pointer = bytes[36];
|
||||
let interrupt_line = bytes[44];
|
||||
let interrupt_pin = bytes[45];
|
||||
@@ -158,7 +158,6 @@ impl PciHeader {
|
||||
let prefetch_limit_upper = LittleEndian::read_u32(&bytes[28..32]);
|
||||
let io_base_upper = LittleEndian::read_u16(&bytes[32..34]);
|
||||
let io_limit_upper = LittleEndian::read_u16(&bytes[34..36]);
|
||||
// TODO: Parse out the capabilities list.
|
||||
let cap_pointer = bytes[36];
|
||||
let expansion_rom = LittleEndian::read_u32(&bytes[40..44]);
|
||||
let interrupt_line = bytes[44];
|
||||
@@ -265,6 +264,11 @@ impl PciHeader {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cap_pointer(&self) -> u8 {
|
||||
match self {
|
||||
&PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => cap_pointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
+23
-4
@@ -1,3 +1,5 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub use self::bar::PciBar;
|
||||
pub use self::bus::{PciBus, PciBusIter};
|
||||
pub use self::class::PciClass;
|
||||
@@ -7,16 +9,22 @@ pub use self::header::{PciHeader, PciHeaderError, PciHeaderType};
|
||||
|
||||
mod bar;
|
||||
mod bus;
|
||||
pub mod cap;
|
||||
mod class;
|
||||
mod dev;
|
||||
mod func;
|
||||
pub mod header;
|
||||
pub mod msi;
|
||||
|
||||
pub struct Pci;
|
||||
pub struct Pci {
|
||||
lock: Mutex<()>,
|
||||
}
|
||||
|
||||
impl Pci {
|
||||
pub fn new() -> Self {
|
||||
Pci
|
||||
Self {
|
||||
lock: Mutex::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buses<'pci>(&'pci self) -> PciIter<'pci> {
|
||||
@@ -24,7 +32,7 @@ impl Pci {
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
|
||||
pub unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
|
||||
let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC);
|
||||
let value: u32;
|
||||
asm!("mov dx, 0xCF8
|
||||
@@ -36,7 +44,13 @@ impl Pci {
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) {
|
||||
pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
self.read_nolock(bus, dev, func, offset)
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) {
|
||||
let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC);
|
||||
asm!("mov dx, 0xCF8
|
||||
out dx, eax"
|
||||
@@ -45,6 +59,11 @@ impl Pci {
|
||||
out dx, eax"
|
||||
: : "{eax}"(value) : "dx" : "intel", "volatile");
|
||||
}
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
self.write_nolock(bus, dev, func, offset, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PciIter<'pci> {
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
use std::fmt;
|
||||
|
||||
use super::bar::PciBar;
|
||||
pub use super::cap::{MsiCapability, MsixCapability};
|
||||
use super::func::{ConfigReader, ConfigWriter};
|
||||
|
||||
use syscall::{Io, Mmio};
|
||||
|
||||
impl MsiCapability {
|
||||
pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8;
|
||||
pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7;
|
||||
|
||||
pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E;
|
||||
pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1;
|
||||
|
||||
pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070;
|
||||
pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4;
|
||||
|
||||
pub const MC_MSI_ENABLED_BIT: u16 = 1;
|
||||
|
||||
pub unsafe fn parse<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
let dword = reader.read_u32(offset);
|
||||
|
||||
let message_control = (dword >> 16) as u16;
|
||||
|
||||
if message_control & Self::MC_PVT_CAPABLE_BIT != 0 {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddressWithPvm {
|
||||
message_control: dword,
|
||||
message_address_lo: reader.read_u32(offset + 4),
|
||||
message_address_hi: reader.read_u32(offset + 8),
|
||||
message_data: reader.read_u32(offset + 12),
|
||||
mask_bits: reader.read_u32(offset + 16),
|
||||
pending_bits: reader.read_u32(offset + 20),
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddressWithPvm {
|
||||
message_control: dword,
|
||||
message_address: reader.read_u32(offset + 4),
|
||||
message_data: reader.read_u32(offset + 8),
|
||||
mask_bits: reader.read_u32(offset + 12),
|
||||
pending_bits: reader.read_u32(offset + 16),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddress {
|
||||
message_control: dword,
|
||||
message_address_lo: reader.read_u32(offset + 4),
|
||||
message_address_hi: reader.read_u32(offset + 8),
|
||||
message_data: reader.read_u32(offset + 12),
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddress {
|
||||
message_control: dword,
|
||||
message_address: reader.read_u32(offset + 4),
|
||||
message_data: reader.read_u32(offset + 8),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn message_control_raw(&self) -> u32 {
|
||||
match self {
|
||||
Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control,
|
||||
}
|
||||
}
|
||||
pub fn message_control(&self) -> u16 {
|
||||
(self.message_control_raw() >> 16) as u16
|
||||
}
|
||||
pub fn set_message_control(&mut self, value: u16) {
|
||||
let mut new_message_control = self.message_control_raw();
|
||||
new_message_control &= 0x0000_FFFF;
|
||||
new_message_control |= u32::from(value) << 16;
|
||||
|
||||
match self {
|
||||
Self::_32BitAddress { ref mut message_control, .. }
|
||||
| Self::_64BitAddress { ref mut message_control, .. }
|
||||
| Self::_32BitAddressWithPvm { ref mut message_control, .. }
|
||||
| Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control,
|
||||
}
|
||||
}
|
||||
pub unsafe fn write_message_control<W: ConfigWriter>(&mut self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset, self.message_control_raw());
|
||||
}
|
||||
pub fn is_pvt_capable(&self) -> bool {
|
||||
self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0
|
||||
}
|
||||
pub fn has_64_bit_addr(&self) -> bool {
|
||||
self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0
|
||||
}
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.message_control() & Self::MC_MSI_ENABLED_BIT != 0
|
||||
}
|
||||
pub fn set_enabled(&mut self, enabled: bool) {
|
||||
let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT);
|
||||
new_message_control |= u16::from(enabled);
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
pub fn multi_message_capable(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8
|
||||
}
|
||||
pub fn multi_message_enabled(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8
|
||||
}
|
||||
pub fn set_multi_message_enabled(&mut self, log_mme: u8) {
|
||||
let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK);
|
||||
new_message_control |= (u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT);
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
}
|
||||
|
||||
impl MsixCapability {
|
||||
pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15;
|
||||
pub const MC_MSIX_ENABLED_SHIFT: u8 = 15;
|
||||
pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14;
|
||||
pub const MC_FUNCTION_MASK_SHIFT: u8 = 14;
|
||||
pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF;
|
||||
|
||||
/// The Message Control field, containing the enabled and function mask bits, as well as the
|
||||
/// table size.
|
||||
pub const fn message_control(&self) -> u16 {
|
||||
(self.a >> 16) as u16
|
||||
}
|
||||
|
||||
pub fn set_message_control(&mut self, message_control: u16) {
|
||||
self.a &= 0x0000_FFFF;
|
||||
self.a |= u32::from(message_control) << 16;
|
||||
}
|
||||
/// Returns the MSI-X table size, subtracted by one.
|
||||
pub const fn table_size_raw(&self) -> u16 {
|
||||
self.message_control() & Self::MC_TABLE_SIZE_MASK
|
||||
}
|
||||
/// Returns the MSI-X table size.
|
||||
pub const fn table_size(&self) -> u16 {
|
||||
self.table_size_raw() + 1
|
||||
}
|
||||
/// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the
|
||||
/// MSI capability structure.
|
||||
pub const fn msix_enabled(&self) -> bool {
|
||||
self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0
|
||||
}
|
||||
/// The MSI-X function mask, which overrides each of the vectors' mask bit, when set.
|
||||
pub const fn function_mask(&self) -> bool {
|
||||
self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0
|
||||
}
|
||||
|
||||
pub fn set_msix_enabled(&mut self, enabled: bool) {
|
||||
let mut new_message_control = self.message_control();
|
||||
new_message_control &= !(Self::MC_MSIX_ENABLED_BIT);
|
||||
new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT;
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
|
||||
pub fn set_function_mask(&mut self, function_mask: bool) {
|
||||
let mut new_message_control = self.message_control();
|
||||
new_message_control &= !(Self::MC_FUNCTION_MASK_BIT);
|
||||
new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT;
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8;
|
||||
pub const TABLE_BIR_MASK: u32 = 0x0000_0007;
|
||||
|
||||
/// The table offset is guaranteed to be QWORD aligned (8 bytes).
|
||||
pub const fn table_offset(&self) -> u32 {
|
||||
self.b & Self::TABLE_OFFSET_MASK
|
||||
}
|
||||
/// The table BIR, which is used to map the offset to a memory location.
|
||||
pub const fn table_bir(&self) -> u8 {
|
||||
(self.b & Self::TABLE_BIR_MASK) as u8
|
||||
}
|
||||
|
||||
pub fn set_table_offset(&mut self, offset: u32) {
|
||||
assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned");
|
||||
self.b &= !Self::TABLE_OFFSET_MASK;
|
||||
self.b |= offset;
|
||||
}
|
||||
pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8;
|
||||
pub const PBA_BIR_MASK: u32 = 0x0000_0007;
|
||||
|
||||
/// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes).
|
||||
pub const fn pba_offset(&self) -> u32 {
|
||||
self.c & Self::PBA_OFFSET_MASK
|
||||
}
|
||||
/// The Pending Bit Array BIR, which is used to map the offset to a memory location.
|
||||
pub const fn pba_bir(&self) -> u8 {
|
||||
(self.c & Self::PBA_BIR_MASK) as u8
|
||||
}
|
||||
|
||||
pub fn set_pba_offset(&mut self, offset: u32) {
|
||||
assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned");
|
||||
self.c &= !Self::PBA_OFFSET_MASK;
|
||||
self.c |= offset;
|
||||
}
|
||||
|
||||
pub fn table_base_pointer(&self, bars: [PciBar; 6]) -> usize {
|
||||
if self.table_bir() > 5 {
|
||||
panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir());
|
||||
}
|
||||
let base = bars[usize::from(self.table_bir())];
|
||||
|
||||
if let PciBar::Memory(ptr) = base {
|
||||
ptr as usize + self.table_offset() as usize
|
||||
} else {
|
||||
panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base);
|
||||
}
|
||||
}
|
||||
pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.table_base_pointer(bars) + k as usize * 16
|
||||
}
|
||||
|
||||
pub fn pba_base_pointer(&self, bars: [PciBar; 6]) -> usize {
|
||||
if self.pba_bir() > 5 {
|
||||
panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir());
|
||||
}
|
||||
let base = bars[usize::from(self.pba_bir())];
|
||||
|
||||
if let PciBar::Memory(ptr) = base {
|
||||
ptr as usize + self.pba_offset() as usize
|
||||
} else {
|
||||
panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base);
|
||||
}
|
||||
}
|
||||
pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.pba_base_pointer(bars) + (k as usize / 32) * 4
|
||||
}
|
||||
pub const fn pba_bit_dword(&self, k: u16) -> u8 {
|
||||
(k % 32) as u8
|
||||
}
|
||||
|
||||
pub fn pba_pointer_qword(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.pba_base_pointer(bars) + (k as usize / 64) * 8
|
||||
}
|
||||
pub const fn pba_bit_qword(&self, k: u16) -> u8 {
|
||||
(k % 64) as u8
|
||||
}
|
||||
|
||||
/// Write the first DWORD into configuration space (containing the partially modifiable Message
|
||||
/// Control field).
|
||||
pub unsafe fn write_a<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset, self.a)
|
||||
}
|
||||
/// Write the second DWORD into configuration space (containing the modifiable table
|
||||
/// offset and the readonly table BIR).
|
||||
pub unsafe fn write_b<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset + 4, self.a)
|
||||
}
|
||||
/// Write the third DWORD into configuration space (containing the modifiable pending bit array
|
||||
/// offset, and the readonly PBA BIR).
|
||||
pub unsafe fn write_c<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset + 8, self.a)
|
||||
}
|
||||
/// Write this capability structure back to configuration space.
|
||||
pub unsafe fn write_all<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
self.write_a(writer, offset);
|
||||
self.write_b(writer, offset);
|
||||
self.write_c(writer, offset);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct MsixTableEntry {
|
||||
pub addr_lo: Mmio<u32>,
|
||||
pub addr_hi: Mmio<u32>,
|
||||
pub msg_data: Mmio<u32>,
|
||||
pub vec_ctl: Mmio<u32>,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod x86_64 {
|
||||
#[repr(u8)]
|
||||
pub enum TriggerMode {
|
||||
Edge = 0,
|
||||
Level = 1,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum LevelTriggerMode {
|
||||
Deassert = 0,
|
||||
Assert = 1,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DeliveryMode {
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001,
|
||||
Smi = 0b010,
|
||||
// 0b011 is reserved
|
||||
Nmi = 0b100,
|
||||
Init = 0b101,
|
||||
// 0b110 is reserved
|
||||
ExtInit = 0b111,
|
||||
}
|
||||
|
||||
// TODO: should the reserved field be preserved?
|
||||
pub const fn message_address(destination_id: u8, rh: bool, dm: bool, xx: u8) -> u32 {
|
||||
0xFEE0_0000u32
|
||||
| ((destination_id as u32) << 12)
|
||||
| ((rh as u32) << 3)
|
||||
| ((dm as u32) << 2)
|
||||
| xx as u32
|
||||
}
|
||||
pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 {
|
||||
((trigger_mode as u32) << 15)
|
||||
| ((level_trigger_mode as u32) << 14)
|
||||
| ((delivery_mode as u32) << 8)
|
||||
| vector as u32
|
||||
}
|
||||
pub const fn message_data_level_triggered(level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 {
|
||||
message_data(TriggerMode::Level, level_trigger_mode, delivery_mode, vector)
|
||||
}
|
||||
pub const fn message_data_edge_triggered(delivery_mode: DeliveryMode, vector: u8) -> u32 {
|
||||
message_data(TriggerMode::Edge, LevelTriggerMode::Deassert, delivery_mode, vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl MsixTableEntry {
|
||||
pub fn addr_lo(&self) -> u32 {
|
||||
self.addr_lo.read()
|
||||
}
|
||||
pub fn addr_hi(&self) -> u32 {
|
||||
self.addr_hi.read()
|
||||
}
|
||||
pub fn msg_data(&self) -> u32 {
|
||||
self.msg_data.read()
|
||||
}
|
||||
pub fn vec_ctl(&self) -> u32 {
|
||||
self.vec_ctl.read()
|
||||
}
|
||||
pub fn addr(&self) -> u64 {
|
||||
u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32)
|
||||
}
|
||||
pub const VEC_CTL_MASK_BIT: u32 = 1;
|
||||
|
||||
pub fn mask(&mut self) {
|
||||
self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, true)
|
||||
}
|
||||
pub fn unmask(&mut self) {
|
||||
self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, false)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for MsixTableEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("MsixTableEntry")
|
||||
.field("addr", &self.addr())
|
||||
.field("msg_data", &self.msg_data())
|
||||
.field("vec_ctl", &self.vec_ctl())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -13,13 +13,18 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1"
|
||||
chashmap = { git = "https://gitlab.redox-os.org/redox-os/chashmap.git" }
|
||||
crossbeam-channel = "0.4"
|
||||
futures = "0.3"
|
||||
plain = "0.2"
|
||||
lazy_static = "1.4"
|
||||
spin = "0.4"
|
||||
log = "0.4"
|
||||
redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" }
|
||||
redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" }
|
||||
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
smallvec = { version = "1", features = ["serde"] }
|
||||
thiserror = "1"
|
||||
toml = "0.5"
|
||||
pcid = { path = "../pcid" }
|
||||
|
||||
@@ -14,7 +14,7 @@ use thiserror::Error;
|
||||
|
||||
pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct ConfigureEndpointsReq {
|
||||
/// Index into the configuration descriptors of the device descriptor.
|
||||
pub config_desc: u8,
|
||||
|
||||
+242
-104
@@ -1,140 +1,278 @@
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate event;
|
||||
extern crate plain;
|
||||
extern crate syscall;
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::fs::{self, File};
|
||||
use std::future::Future;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::env;
|
||||
|
||||
use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo};
|
||||
use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry};
|
||||
|
||||
use event::{Event, EventQueue};
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Result, Write};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::sync::Arc;
|
||||
use std::{env, io};
|
||||
use log::info;
|
||||
use syscall::data::Packet;
|
||||
use syscall::error::EWOULDBLOCK;
|
||||
use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE};
|
||||
use syscall::scheme::SchemeMut;
|
||||
use syscall::scheme::Scheme;
|
||||
use syscall::io::Io;
|
||||
|
||||
use crate::xhci::Xhci;
|
||||
use crate::xhci::{InterruptMethod, Xhci};
|
||||
|
||||
// Declare as pub so that no warnings appear due to parts of the interface code not being used by
|
||||
// the driver. Since there's also a dedicated crate for the driver interface, those warnings don't
|
||||
// mean anything.
|
||||
pub mod driver_interface;
|
||||
|
||||
mod driver_interface;
|
||||
mod usb;
|
||||
mod xhci;
|
||||
|
||||
/// Read the local APIC id of the bootstrap processor.
|
||||
fn read_bsp_apic_id() -> io::Result<u32> {
|
||||
let mut buffer = [0u8; 8];
|
||||
|
||||
let mut file = File::open("irq:bsp")?;
|
||||
let bytes_read = file.read(&mut buffer)?;
|
||||
|
||||
Ok(if bytes_read == 8 {
|
||||
u64::from_le_bytes(buffer) as u32
|
||||
} else if bytes_read == 4 {
|
||||
u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]])
|
||||
} else {
|
||||
panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::<usize>());
|
||||
})
|
||||
}
|
||||
/// Allocate an interrupt vector, located at the BSP's IDT.
|
||||
fn allocate_interrupt_vector() -> io::Result<Option<(u8, File)>> {
|
||||
let available_irqs = fs::read_dir("irq:")?;
|
||||
|
||||
for entry in available_irqs {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
let file_name = match path.file_name() {
|
||||
Some(f) => f,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let path_str = match file_name.to_str() {
|
||||
Some(s) => s,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if let Ok(irq_number) = path_str.parse::<u8>() {
|
||||
// if found, reserve the irq
|
||||
let irq_handle = File::create(format!("irq:{}", irq_number))?;
|
||||
let interrupt_vector = irq_number + 32;
|
||||
return Ok(Some((interrupt_vector, irq_handle)));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn handle_packet(hci: Arc<Xhci>, packet: Packet) -> Packet {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
|
||||
let mut name = args.next().expect("xhcid: no name provided");
|
||||
name.push_str("_xhci");
|
||||
|
||||
let bar_str = args.next().expect("xhcid: no address provided");
|
||||
let bar = usize::from_str_radix(&bar_str, 16).expect("xhcid: failed to parse address");
|
||||
// Daemonize
|
||||
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let irq_str = args.next().expect("xhcid: no IRQ provided");
|
||||
let irq = irq_str.parse::<u8>().expect("xhcid: failed to parse irq");
|
||||
match redox_log::RedoxLogger::new("usb", "host", "xhci.log") {
|
||||
Ok(logger) => match logger.with_stdout_mirror().enable() {
|
||||
Ok(_) => {
|
||||
println!("xhcid: enabled logger");
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
}
|
||||
Err(error) => eprintln!("xhcid: failed to set default logger: {}", error),
|
||||
}
|
||||
Err(error) => eprintln!("xhcid: failed to initialize logger: {}", error),
|
||||
}
|
||||
|
||||
let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid");
|
||||
let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config");
|
||||
info!("XHCI PCI CONFIG: {:?}", pci_config);
|
||||
|
||||
let bar = pci_config.func.bars[0];
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
let bar_ptr = match bar {
|
||||
pcid_interface::PciBar::Memory(ptr) => ptr,
|
||||
other => panic!("Expected memory bar, found {}", other),
|
||||
};
|
||||
|
||||
let address = unsafe {
|
||||
syscall::physmap(bar_ptr as usize, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)
|
||||
.expect("xhcid: failed to map address")
|
||||
};
|
||||
|
||||
let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features");
|
||||
info!("XHCI PCI FEATURES: {:?}", all_pci_features);
|
||||
|
||||
let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
|
||||
dbg!(has_msi, msi_enabled);
|
||||
dbg!(has_msix, msix_enabled);
|
||||
|
||||
if has_msi && !msi_enabled && !has_msix {
|
||||
pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI");
|
||||
info!("Enabled MSI");
|
||||
msi_enabled = true;
|
||||
}
|
||||
if has_msix && !msix_enabled {
|
||||
pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X");
|
||||
info!("Enabled MSI-X");
|
||||
msix_enabled = true;
|
||||
}
|
||||
|
||||
let (mut irq_file, interrupt_method) = if msi_enabled && !msix_enabled {
|
||||
let mut capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(s) => s,
|
||||
PciFeatureInfo::MsiX(_) => panic!(),
|
||||
};
|
||||
// use one vector
|
||||
capability.set_multi_message_enabled(0);
|
||||
|
||||
todo!("msi (msix is implemented though)")
|
||||
} else if msix_enabled {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(_) => panic!(),
|
||||
PciFeatureInfo::MsiX(s) => s,
|
||||
};
|
||||
let table_size = capability.table_size();
|
||||
let table_base = capability.table_base_pointer(pci_config.func.bars);
|
||||
let table_min_length = table_size * 16;
|
||||
let pba_min_length = crate::xhci::scheme::div_round_up(table_size, 8);
|
||||
|
||||
let pba_base = capability.pba_base_pointer(pci_config.func.bars);
|
||||
dbg!(table_size, table_base, table_min_length, pba_base);
|
||||
|
||||
if !(bar_ptr..bar_ptr + 65536).contains(&(table_base as u32 + table_min_length as u32)) {
|
||||
todo!()
|
||||
}
|
||||
if !(bar_ptr..bar_ptr + 65536).contains(&(pba_base as u32 + pba_min_length as u32)) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry;
|
||||
let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64;
|
||||
|
||||
let mut info = xhci::MsixInfo {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
virt_pba_base: NonNull::new(virt_pba_base).unwrap(),
|
||||
capability,
|
||||
};
|
||||
|
||||
// Allocate one msi vector.
|
||||
|
||||
{
|
||||
use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix};
|
||||
|
||||
// primary interrupter
|
||||
let k = 0;
|
||||
|
||||
assert_eq!(std::mem::size_of::<MsixTableEntry>(), 16);
|
||||
let table_entry_pointer = info.table_entry_pointer(k);
|
||||
|
||||
let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id");
|
||||
let rh = false;
|
||||
let dm = false;
|
||||
let addr = x86_64_msix::message_address(destination_id.try_into().expect("xhcid: BSP apic id couldn't fit u8"), rh, dm, 0b00);
|
||||
|
||||
let (vector, interrupt_handle) = allocate_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left");
|
||||
let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector);
|
||||
|
||||
table_entry_pointer.addr_lo.write(addr);
|
||||
table_entry_pointer.addr_hi.write(0);
|
||||
table_entry_pointer.msg_data.write(msg_data);
|
||||
table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false);
|
||||
|
||||
(Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info)))
|
||||
}
|
||||
} else if pci_config.func.legacy_interrupt_pin.is_some() {
|
||||
// legacy INTx# interrupt pins.
|
||||
(Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx)
|
||||
} else {
|
||||
// no interrupts at all
|
||||
(None, InterruptMethod::Polling)
|
||||
};
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(300));
|
||||
|
||||
print!(
|
||||
"{}",
|
||||
format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq)
|
||||
format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq)
|
||||
);
|
||||
|
||||
// Daemonize
|
||||
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 {
|
||||
let socket_fd = syscall::open(
|
||||
format!(":usb/{}", name),
|
||||
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.expect("xhcid: failed to create usb scheme");
|
||||
let socket = Arc::new(RefCell::new(unsafe {
|
||||
File::from_raw_fd(socket_fd as RawFd)
|
||||
}));
|
||||
let socket_fd = syscall::open(
|
||||
format!(":usb/{}", name),
|
||||
syscall::O_RDWR | syscall::O_CREAT,
|
||||
)
|
||||
.expect("xhcid: failed to create usb scheme");
|
||||
let socket = Arc::new(Mutex::new(unsafe {
|
||||
File::from_raw_fd(socket_fd as RawFd)
|
||||
}));
|
||||
|
||||
let mut irq_file =
|
||||
File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
|
||||
let hci = Arc::new(Xhci::new(name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device"));
|
||||
xhci::start_irq_reactor(&hci, irq_file);
|
||||
futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe");
|
||||
|
||||
let address = unsafe {
|
||||
syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)
|
||||
.expect("xhcid: failed to map address")
|
||||
};
|
||||
{
|
||||
let hci = Arc::new(RefCell::new(
|
||||
Xhci::new(name, address).expect("xhcid: failed to allocate device"),
|
||||
));
|
||||
let mut event_queue =
|
||||
EventQueue::<()>::new().expect("xhcid: failed to create event queue");
|
||||
|
||||
hci.borrow_mut().probe().expect("xhcid: failed to probe");
|
||||
syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace");
|
||||
|
||||
let mut event_queue =
|
||||
EventQueue::<()>::new().expect("xhcid: failed to create event queue");
|
||||
let todo = Arc::new(Mutex::new(Vec::<Packet>::new()));
|
||||
let todo_futures = Arc::new(Mutex::new(Vec::<Pin<Box<dyn Future<Output = usize> + Send + Sync + 'static>>>::new()));
|
||||
|
||||
syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace");
|
||||
let socket_fd = socket.lock().unwrap().as_raw_fd();
|
||||
let socket_packet = socket.clone();
|
||||
event_queue
|
||||
.add(socket_fd, move |_| -> io::Result<Option<()>> {
|
||||
let mut socket = socket_packet.lock().unwrap();
|
||||
let mut todo = todo.lock().unwrap();
|
||||
|
||||
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
match socket.read(&mut packet) {
|
||||
Ok(0) => break,
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
let hci_irq = hci.clone();
|
||||
let socket_irq = socket.clone();
|
||||
let todo_irq = todo.clone();
|
||||
event_queue
|
||||
.add(irq_file.as_raw_fd(), move |_| -> Result<Option<()>> {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.read(&mut irq)?;
|
||||
let a = packet.a;
|
||||
hci.handle(&mut packet);
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.push(packet);
|
||||
} else {
|
||||
socket.write(&packet)?;
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on scheme file");
|
||||
|
||||
if hci_irq.borrow_mut().trigger_irq() {
|
||||
irq_file.write(&mut irq)?;
|
||||
event_queue
|
||||
.trigger_all(Event { fd: 0, flags: 0 })
|
||||
.expect("xhcid: failed to trigger events");
|
||||
|
||||
let mut todo = todo_irq.borrow_mut();
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let a = todo[i].a;
|
||||
hci_irq.borrow_mut().handle(&mut todo[i]);
|
||||
if todo[i].a == (-EWOULDBLOCK) as usize {
|
||||
todo[i].a = a;
|
||||
i += 1;
|
||||
} else {
|
||||
socket_irq.borrow_mut().write(&mut todo[i])?;
|
||||
todo.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
event_queue.run().expect("xhcid: failed to handle events");
|
||||
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on IRQ file");
|
||||
|
||||
let socket_fd = socket.borrow().as_raw_fd();
|
||||
let socket_packet = socket.clone();
|
||||
event_queue
|
||||
.add(socket_fd, move |_| -> Result<Option<()>> {
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
match socket_packet.borrow_mut().read(&mut packet) {
|
||||
Ok(0) => break,
|
||||
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
let a = packet.a;
|
||||
hci.borrow_mut().handle(&mut packet);
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.borrow_mut().push(packet);
|
||||
} else {
|
||||
socket_packet.borrow_mut().write(&mut packet)?;
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on scheme file");
|
||||
|
||||
event_queue
|
||||
.trigger_all(Event { fd: 0, flags: 0 })
|
||||
.expect("xhcid: failed to trigger events");
|
||||
|
||||
event_queue.run().expect("xhcid: failed to handle events");
|
||||
}
|
||||
unsafe {
|
||||
let _ = syscall::physunmap(address);
|
||||
}
|
||||
unsafe {
|
||||
let _ = syscall::physunmap(address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,13 @@ pub const HCS_PARAMS1_MAX_PORTS_SHIFT: u8 = 24;
|
||||
pub const HCS_PARAMS1_MAX_SLOTS_MASK: u32 = 0x0000_00FF;
|
||||
pub const HCS_PARAMS1_MAX_SLOTS_SHIFT: u8 = 0;
|
||||
|
||||
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK: u32 = 0xF800_0000;
|
||||
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT: u8 = 27;
|
||||
pub const HCS_PARAMS2_SPR_BIT: u32 = 1 << HCS_PARAMS2_SPR_SHIFT;
|
||||
pub const HCS_PARAMS2_SPR_SHIFT: u8 = 26;
|
||||
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK: u32 = 0x03E0_0000;
|
||||
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT: u8 = 21;
|
||||
|
||||
impl CapabilityRegs {
|
||||
pub fn lec(&self) -> bool {
|
||||
self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT)
|
||||
@@ -48,4 +55,17 @@ impl CapabilityRegs {
|
||||
pub fn ext_caps_ptr_in_dwords(&self) -> u16 {
|
||||
((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16
|
||||
}
|
||||
pub fn max_scratchpad_bufs_lo(&self) -> u8 {
|
||||
((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8
|
||||
}
|
||||
pub fn spr(&self) -> bool {
|
||||
self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT)
|
||||
}
|
||||
pub fn max_scratchpad_bufs_hi(&self) -> u8 {
|
||||
((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8
|
||||
}
|
||||
pub fn max_scratchpad_bufs(&self) -> u16 {
|
||||
u16::from(self.max_scratchpad_bufs_lo())
|
||||
| (u16::from(self.max_scratchpad_bufs_hi()) << 5)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
use syscall::error::Result;
|
||||
|
||||
use super::event::EventRing;
|
||||
use super::ring::Ring;
|
||||
use super::trb::Trb;
|
||||
|
||||
pub struct CommandRing {
|
||||
pub ring: Ring,
|
||||
pub events: EventRing,
|
||||
}
|
||||
|
||||
impl CommandRing {
|
||||
pub fn new() -> Result<CommandRing> {
|
||||
Ok(CommandRing {
|
||||
ring: Ring::new(16, true)?,
|
||||
events: EventRing::new()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn crcr(&self) -> u64 {
|
||||
self.ring.register()
|
||||
}
|
||||
|
||||
pub fn erdp(&self) -> u64 {
|
||||
self.events.ring.register()
|
||||
}
|
||||
|
||||
pub fn erstba(&self) -> u64 {
|
||||
self.events.ste.physical() as u64
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> (&mut Trb, bool, &mut Trb) {
|
||||
let cmd = self.ring.next();
|
||||
let event = self.events.next();
|
||||
(cmd.0, cmd.1, event)
|
||||
}
|
||||
|
||||
pub fn next_cmd(&mut self) -> (&mut Trb, bool) {
|
||||
self.ring.next()
|
||||
}
|
||||
|
||||
pub fn next_event(&mut self) -> &mut Trb {
|
||||
self.events.next()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use log::debug;
|
||||
use syscall::error::Result;
|
||||
use syscall::io::{Dma, Io, Mmio};
|
||||
|
||||
@@ -59,7 +60,7 @@ pub struct InputContext {
|
||||
}
|
||||
impl InputContext {
|
||||
pub fn dump_control(&self) {
|
||||
println!(
|
||||
debug!(
|
||||
"INPUT CONTEXT: {} {} [{} {} {} {} {}] {}",
|
||||
self.drop_context.read(),
|
||||
self.add_context.read(),
|
||||
@@ -75,7 +76,7 @@ impl InputContext {
|
||||
|
||||
pub struct DeviceContextList {
|
||||
pub dcbaa: Dma<[u64; 256]>,
|
||||
pub contexts: Vec<Dma<DeviceContext>>,
|
||||
pub contexts: Box<[Dma<DeviceContext>]>,
|
||||
}
|
||||
|
||||
impl DeviceContextList {
|
||||
@@ -91,8 +92,8 @@ impl DeviceContextList {
|
||||
}
|
||||
|
||||
Ok(DeviceContextList {
|
||||
dcbaa: dcbaa,
|
||||
contexts: contexts,
|
||||
dcbaa,
|
||||
contexts: contexts.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -159,3 +160,38 @@ impl StreamContextArray {
|
||||
self.contexts.physical() as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct ScratchpadBufferEntry {
|
||||
pub value: Mmio<u64>,
|
||||
}
|
||||
impl ScratchpadBufferEntry {
|
||||
pub fn set_addr(&mut self, addr: u64) {
|
||||
self.value.write(addr);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ScratchpadBufferArray {
|
||||
pub entries: Dma<[ScratchpadBufferEntry]>,
|
||||
pub pages: Vec<usize>,
|
||||
}
|
||||
impl ScratchpadBufferArray {
|
||||
pub fn new(page_size: usize, entries: u16) -> Result<Self> {
|
||||
let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? };
|
||||
|
||||
let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result<usize> {
|
||||
let pointer = unsafe { syscall::physalloc(page_size)? };
|
||||
assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned");
|
||||
entry.set_addr(pointer as u64);
|
||||
Ok(pointer)
|
||||
}).collect::<Result<Vec<usize>, _>>()?;
|
||||
|
||||
Ok(Self {
|
||||
entries,
|
||||
pages,
|
||||
})
|
||||
}
|
||||
pub fn register(&self) -> usize {
|
||||
self.entries.physical()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ pub struct EventRingSte {
|
||||
_rsvd2: Mmio<u32>,
|
||||
}
|
||||
|
||||
// TODO: Use atomic operations, and perhaps an occasional lock for reallocating.
|
||||
pub struct EventRing {
|
||||
pub ste: Dma<[EventRingSte]>,
|
||||
pub ring: Ring,
|
||||
@@ -33,4 +34,10 @@ impl EventRing {
|
||||
pub fn next(&mut self) -> &mut Trb {
|
||||
self.ring.next().0
|
||||
}
|
||||
pub fn erdp(&self) -> u64 {
|
||||
self.ring.register() & 0xFFFF_FFFF_FFFF_FFF0
|
||||
}
|
||||
pub fn erstba(&self) -> u64 {
|
||||
self.ste.physical() as u64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,468 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::future::Future;
|
||||
use std::io::prelude::*;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::atomic::{self, AtomicUsize};
|
||||
use std::{io, mem, task, thread};
|
||||
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use crossbeam_channel::{Sender, Receiver};
|
||||
use log::{debug, error, info, warn, trace};
|
||||
use futures::Stream;
|
||||
use syscall::Io;
|
||||
|
||||
use event::{Event, EventQueue};
|
||||
|
||||
use super::Xhci;
|
||||
use super::ring::Ring;
|
||||
use super::trb::{Trb, TrbCompletionCode, TrbType};
|
||||
use super::event::EventRing;
|
||||
|
||||
/// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back
|
||||
/// by the future unless it completed).
|
||||
#[derive(Debug)]
|
||||
pub struct State {
|
||||
waker: task::Waker,
|
||||
kind: StateKind,
|
||||
message: Arc<Mutex<Option<NextEventTrb>>>,
|
||||
is_isoch_or_vf: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NextEventTrb {
|
||||
pub event_trb: Trb,
|
||||
pub src_trb: Option<Trb>,
|
||||
}
|
||||
|
||||
// TODO: Perhaps all of the transfer rings used by the xHC should be stored linearly, and then
|
||||
// indexed using this struct instead.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct RingId {
|
||||
pub port: u8,
|
||||
pub endpoint_num: u8,
|
||||
pub stream_id: u16,
|
||||
}
|
||||
impl RingId {
|
||||
pub const fn default_control_pipe(port: u8) -> Self {
|
||||
Self {
|
||||
port,
|
||||
endpoint_num: 0,
|
||||
stream_id: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for
|
||||
/// example the Command Completion Event and the Transfer Event TDs, they have to be
|
||||
/// distinguishable. Luckily, the xHC also gives us the actual (physical) pointer to the source
|
||||
/// TRB, from the command ring, unless the event TD has one the completion codes Ring Underrun,
|
||||
/// Ring Overrun, or VF Event Ring Full Error. When these errors are encountered, it simply
|
||||
/// indicates that the commands causing the errors continue to be pending, and thus no information
|
||||
/// is lost.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum StateKind {
|
||||
CommandCompletion { phys_ptr: u64 },
|
||||
Transfer { phys_ptr: u64, ring_id: RingId },
|
||||
Other(TrbType),
|
||||
}
|
||||
|
||||
impl StateKind {
|
||||
pub fn trb_type(&self) -> TrbType {
|
||||
match self {
|
||||
&Self::CommandCompletion { .. } => TrbType::CommandCompletion,
|
||||
&Self::Transfer { .. } => TrbType::Transfer,
|
||||
&Self::Other(ty) => ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct IrqReactor {
|
||||
hci: Arc<Xhci>,
|
||||
irq_file: Option<File>,
|
||||
receiver: Receiver<NewPendingTrb>,
|
||||
|
||||
states: Vec<State>,
|
||||
|
||||
// TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps
|
||||
// the event ring should be owned here?
|
||||
}
|
||||
|
||||
pub type NewPendingTrb = State;
|
||||
|
||||
impl IrqReactor {
|
||||
pub fn new(hci: Arc<Xhci>, receiver: Receiver<NewPendingTrb>, irq_file: Option<File>) -> Self {
|
||||
Self {
|
||||
hci,
|
||||
irq_file,
|
||||
receiver,
|
||||
states: Vec::new(),
|
||||
}
|
||||
}
|
||||
// TODO: Configure the amount of time wait when no more work can be done (for IRQ-less polling).
|
||||
fn pause(&self) {
|
||||
std::thread::yield_now();
|
||||
}
|
||||
fn run_polling(mut self) {
|
||||
debug!("Running IRQ reactor in polling mode.");
|
||||
let hci_clone = Arc::clone(&self.hci);
|
||||
|
||||
'event_loop: loop {
|
||||
let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap();
|
||||
|
||||
let index = event_ring_guard.ring.next_index();
|
||||
|
||||
let mut trb;
|
||||
|
||||
'busy_waiting: loop {
|
||||
trb = &event_ring_guard.ring.trbs[index];
|
||||
|
||||
if trb.completion_code() == TrbCompletionCode::Invalid as u8 {
|
||||
self.pause();
|
||||
continue 'busy_waiting;
|
||||
}
|
||||
}
|
||||
if self.check_event_ring_full(trb.clone()) { continue 'event_loop }
|
||||
|
||||
self.handle_requests();
|
||||
self.acknowledge(trb.clone());
|
||||
|
||||
self.update_erdp(&*event_ring_guard);
|
||||
}
|
||||
}
|
||||
fn run_with_irq_file(mut self) {
|
||||
debug!("Running IRQ reactor with IRQ file and event queue");
|
||||
|
||||
let hci_clone = Arc::clone(&self.hci);
|
||||
let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue");
|
||||
let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd();
|
||||
|
||||
let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() };
|
||||
|
||||
event_queue.add(irq_fd, move |_| -> io::Result<Option<()>> {
|
||||
trace!("IRQ event queue notified");
|
||||
let mut buffer = [0u8; 8];
|
||||
|
||||
let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme");
|
||||
|
||||
if !self.hci.received_irq() {
|
||||
// continue only when an IRQ to this device was received
|
||||
trace!("no interrupt pending");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
trace!("IRQ reactor received an IRQ");
|
||||
|
||||
let _ = self.irq_file.as_mut().unwrap().write(&buffer);
|
||||
|
||||
// TODO: More event rings, probably even with different IRQs.
|
||||
|
||||
let mut event_ring = hci_clone.primary_event_ring.lock().unwrap();
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
'trb_loop: loop {
|
||||
let event_trb = &mut event_ring.ring.trbs[event_trb_index];
|
||||
|
||||
if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 {
|
||||
if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") }
|
||||
// no more events were found, continue the loop
|
||||
return Ok(None);
|
||||
} else { count += 1 }
|
||||
|
||||
trace!("Found event TRB: {:?}", event_trb);
|
||||
|
||||
if self.check_event_ring_full(event_trb.clone()) {
|
||||
info!("Had to resize event TRB, retrying...");
|
||||
hci_clone.event_handler_finished();
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
self.handle_requests();
|
||||
self.acknowledge(event_trb.clone());
|
||||
|
||||
event_trb.reserved(false);
|
||||
|
||||
self.update_erdp(&*event_ring);
|
||||
|
||||
event_trb_index = event_ring.ring.next_index();
|
||||
}
|
||||
}).expect("xhcid: failed to catch irq events");
|
||||
event_queue.run().expect("xhcid: failed to run IRQ event queue");
|
||||
}
|
||||
fn update_erdp(&self, event_ring: &EventRing) {
|
||||
let dequeue_pointer_and_dcs = event_ring.erdp();
|
||||
let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE;
|
||||
assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring");
|
||||
|
||||
debug!("Updated ERDP to {:#0x}", dequeue_pointer);
|
||||
|
||||
self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer);
|
||||
}
|
||||
fn handle_requests(&mut self) {
|
||||
self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:?}", req)));
|
||||
}
|
||||
fn acknowledge(&mut self, trb: Trb) {
|
||||
let mut index = 0;
|
||||
|
||||
loop {
|
||||
if index >= self.states.len() { break }
|
||||
|
||||
match self.states[index].kind {
|
||||
StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) {
|
||||
trace!("Found matching command completion future");
|
||||
let state = self.states.remove(index);
|
||||
|
||||
// Before waking, it's crucial that the command TRB that generated this event
|
||||
// is fetched before removing this event TRB from the queue.
|
||||
let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) {
|
||||
Some(command_trb) => {
|
||||
let t = command_trb.clone();
|
||||
command_trb.reserved(false);
|
||||
t
|
||||
},
|
||||
None => {
|
||||
warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Validate the command TRB.
|
||||
*state.message.lock().unwrap() = Some(NextEventTrb {
|
||||
src_trb: Some(command_trb.clone()),
|
||||
event_trb: trb.clone(),
|
||||
});
|
||||
|
||||
trace!("Waking up future with waker: {:?}", state.waker);
|
||||
state.waker.wake();
|
||||
|
||||
return;
|
||||
} else if trb.completion_trb_pointer().is_none() {
|
||||
warn!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb);
|
||||
continue;
|
||||
} else {
|
||||
// The event TRB simply didn't match the current future
|
||||
continue;
|
||||
}
|
||||
|
||||
StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() {
|
||||
if trb.transfer_event_trb_pointer() == Some(phys_ptr) {
|
||||
// Give the source transfer TRB together with the event TRB, to the future.
|
||||
|
||||
let state = self.states.remove(index);
|
||||
*state.message.lock().unwrap() = Some(NextEventTrb {
|
||||
src_trb: Some(src_trb),
|
||||
event_trb: trb.clone(),
|
||||
});
|
||||
state.waker.wake();
|
||||
return;
|
||||
} else if trb.transfer_event_trb_pointer().is_none() {
|
||||
// Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full.
|
||||
//
|
||||
// These errors are caused when either an isoch transfer that shall write data, doesn't
|
||||
// have any data since the ring is empty, or if an isoch receive is impossible due to a
|
||||
// full ring. The Virtual Function Event Ring Full is only for Virtual Machine
|
||||
// Managers, and since this isn't implemented yet, they are irrelevant.
|
||||
//
|
||||
// The best solution here is to differentiate between isoch transfers (and
|
||||
// virtual function event rings when virtualization gets implemented), with
|
||||
// regular commands and transfers, and send the error TRB to all of them, or
|
||||
// possibly an error code wrapped in a Result.
|
||||
self.acknowledge_failed_transfer_trbs(trb);
|
||||
return;
|
||||
} else {
|
||||
// The event TRB simply didn't match the current future
|
||||
continue;
|
||||
}
|
||||
} else { continue }
|
||||
|
||||
StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => {
|
||||
let state = self.states.remove(index);
|
||||
state.waker.wake();
|
||||
return;
|
||||
}
|
||||
|
||||
_ => {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
warn!("Lost event TRB: {:?}", trb);
|
||||
}
|
||||
fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) {
|
||||
let mut index = 0;
|
||||
|
||||
loop {
|
||||
if ! self.states[index].is_isoch_or_vf {
|
||||
index += 1;
|
||||
if index >= self.states.len() {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let state = self.states.remove(index);
|
||||
*state.message.lock().unwrap() = Some(NextEventTrb {
|
||||
event_trb: trb.clone(),
|
||||
src_trb: None,
|
||||
});
|
||||
state.waker.wake();
|
||||
}
|
||||
}
|
||||
/// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring
|
||||
/// Full. If so, it grows the event ring. The return value is whether the event ring was full,
|
||||
/// and then grown.
|
||||
fn check_event_ring_full(&mut self, event_trb: Trb) -> bool {
|
||||
let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8;
|
||||
|
||||
if had_event_ring_full_error {
|
||||
self.grow_event_ring();
|
||||
}
|
||||
had_event_ring_full_error
|
||||
}
|
||||
/// Grows the event ring
|
||||
fn grow_event_ring(&mut self) {
|
||||
// TODO
|
||||
error!("TODO: grow event ring");
|
||||
}
|
||||
|
||||
pub fn run(mut self) {
|
||||
if self.irq_file.is_some() {
|
||||
self.run_with_irq_file();
|
||||
} else {
|
||||
self.run_polling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FutureState {
|
||||
message: Arc<Mutex<Option<NextEventTrb>>>,
|
||||
is_isoch_or_vf: bool,
|
||||
state_kind: StateKind,
|
||||
}
|
||||
|
||||
enum EventTrbFuture {
|
||||
Pending { state: FutureState, sender: Sender<State>, },
|
||||
Finished,
|
||||
}
|
||||
|
||||
impl Future for EventTrbFuture {
|
||||
type Output = NextEventTrb;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
|
||||
let message = match this {
|
||||
&mut Self::Pending { ref state, ref sender } => match state.message.lock().unwrap().take() {
|
||||
Some(message) => message,
|
||||
|
||||
None => {
|
||||
sender.send(State {
|
||||
message: Arc::clone(&state.message),
|
||||
is_isoch_or_vf: state.is_isoch_or_vf,
|
||||
kind: state.state_kind,
|
||||
waker: context.waker().clone(),
|
||||
}).expect("IRQ reactor thread unexpectedly stopped");
|
||||
|
||||
return task::Poll::Pending;
|
||||
}
|
||||
}
|
||||
&mut Self::Finished => panic!("Polling finished EventTrbFuture again."),
|
||||
};
|
||||
*this = Self::Finished;
|
||||
task::Poll::Ready(message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Xhci {
|
||||
pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option<Trb> {
|
||||
self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)).flatten()
|
||||
}
|
||||
pub fn with_ring<T, F: FnOnce(&Ring) -> T>(&self, id: RingId, function: F) -> Option<T> {
|
||||
use super::RingOrStreams;
|
||||
|
||||
let slot_state = self.port_states.get(&(id.port as usize))?;
|
||||
let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?;
|
||||
|
||||
let ring_ref = match endpoint_state.transfer {
|
||||
RingOrStreams::Ring(ref ring) => ring,
|
||||
RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?,
|
||||
};
|
||||
|
||||
Some(function(ring_ref))
|
||||
}
|
||||
pub fn with_ring_mut<T, F: FnOnce(&mut Ring) -> T>(&self, id: RingId, function: F) -> Option<T> {
|
||||
use super::RingOrStreams;
|
||||
|
||||
let mut slot_state = self.port_states.get_mut(&(id.port as usize))?;
|
||||
let mut endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?;
|
||||
|
||||
let ring_ref = match endpoint_state.transfer {
|
||||
RingOrStreams::Ring(ref mut ring) => ring,
|
||||
RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?,
|
||||
};
|
||||
|
||||
Some(function(ring_ref))
|
||||
}
|
||||
pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, trb: &Trb) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
|
||||
if ! trb.is_transfer_trb() {
|
||||
panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb)
|
||||
}
|
||||
|
||||
let is_isoch_or_vf = trb.trb_type() == TrbType::Isoch as u8;
|
||||
|
||||
EventTrbFuture::Pending {
|
||||
state: FutureState {
|
||||
is_isoch_or_vf,
|
||||
state_kind: StateKind::Transfer {
|
||||
ring_id,
|
||||
phys_ptr: ring.trb_phys_ptr(trb),
|
||||
},
|
||||
message: Arc::new(Mutex::new(None)),
|
||||
},
|
||||
sender: self.irq_reactor_sender.clone(),
|
||||
}
|
||||
}
|
||||
pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
|
||||
if ! trb.is_command_trb() {
|
||||
panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb)
|
||||
}
|
||||
dbg!(command_ring.trbs.physical());
|
||||
EventTrbFuture::Pending {
|
||||
state: FutureState {
|
||||
// This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization).
|
||||
is_isoch_or_vf: false,
|
||||
state_kind: StateKind::CommandCompletion {
|
||||
phys_ptr: command_ring.trb_phys_ptr(trb),
|
||||
},
|
||||
message: Arc::new(Mutex::new(None)),
|
||||
},
|
||||
sender: self.irq_reactor_sender.clone(),
|
||||
}
|
||||
}
|
||||
pub fn next_misc_event_trb(&self, trb_type: TrbType) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
|
||||
let valid_trb_types = [
|
||||
TrbType::PortStatusChange as u8,
|
||||
TrbType::BandwidthRequest as u8,
|
||||
TrbType::Doorbell as u8,
|
||||
TrbType::HostController as u8,
|
||||
TrbType::DeviceNotification as u8,
|
||||
TrbType::MfindexWrap as u8,
|
||||
];
|
||||
if ! valid_trb_types.contains(&(trb_type as u8)) {
|
||||
panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type)
|
||||
}
|
||||
EventTrbFuture::Pending {
|
||||
state: FutureState {
|
||||
is_isoch_or_vf: false,
|
||||
state_kind: StateKind::Other(trb_type),
|
||||
message: Arc::new(Mutex::new(None)),
|
||||
},
|
||||
sender: self.irq_reactor_sender.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+363
-228
@@ -1,107 +1,156 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak};
|
||||
use std::{mem, process, slice, sync::atomic, task};
|
||||
use std::sync::{Arc, Mutex, MutexGuard, Weak};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
|
||||
use std::{mem, process, slice, sync::atomic, task, thread};
|
||||
|
||||
use chashmap::CHashMap;
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use serde::Deserialize;
|
||||
use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT};
|
||||
use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO};
|
||||
use syscall::flag::O_RDONLY;
|
||||
use syscall::io::{Dma, Io};
|
||||
|
||||
use crate::usb;
|
||||
|
||||
use pcid_interface::msi::{MsixTableEntry, MsixCapability};
|
||||
use pcid_interface::{PcidServerHandle, PciFeature};
|
||||
|
||||
mod capability;
|
||||
mod command;
|
||||
mod context;
|
||||
mod doorbell;
|
||||
mod event;
|
||||
mod extended;
|
||||
pub mod irq_reactor;
|
||||
mod operational;
|
||||
mod port;
|
||||
mod ring;
|
||||
mod runtime;
|
||||
mod scheme;
|
||||
pub mod scheme;
|
||||
mod trb;
|
||||
|
||||
use self::capability::CapabilityRegs;
|
||||
use self::command::CommandRing;
|
||||
use self::context::{DeviceContextList, InputContext, StreamContextArray};
|
||||
use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray};
|
||||
use self::doorbell::Doorbell;
|
||||
use self::irq_reactor::{IrqReactor, NewPendingTrb, RingId};
|
||||
use self::event::EventRing;
|
||||
use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap};
|
||||
use self::operational::OperationalRegs;
|
||||
use self::port::Port;
|
||||
use self::ring::Ring;
|
||||
use self::runtime::{Interrupter, RuntimeRegs};
|
||||
use self::trb::{TransferKind, TrbCompletionCode, TrbType};
|
||||
use self::trb::{TransferKind, Trb, TrbCompletionCode, TrbType};
|
||||
|
||||
use self::scheme::EndpIfState;
|
||||
|
||||
use crate::driver_interface::*;
|
||||
|
||||
struct Device<'a> {
|
||||
ring: &'a mut Ring,
|
||||
cmd: &'a mut CommandRing,
|
||||
db: &'a mut Doorbell,
|
||||
int: &'a mut Interrupter,
|
||||
pub enum InterruptMethod {
|
||||
/// No interrupts whatsoever; the driver will instead rely on polling event rings.
|
||||
Polling,
|
||||
|
||||
/// Legacy PCI INTx# interrupt pin.
|
||||
Intx,
|
||||
|
||||
/// Message signaled interrupts.
|
||||
Msi,
|
||||
|
||||
/// Extended message signaled interrupts.
|
||||
MsiX(Mutex<MsixInfo>),
|
||||
}
|
||||
|
||||
impl<'a> Device<'a> {
|
||||
fn get_desc<T>(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma<T>) {
|
||||
pub struct MsixInfo {
|
||||
pub virt_table_base: NonNull<MsixTableEntry>,
|
||||
pub virt_pba_base: NonNull<u64>,
|
||||
pub capability: MsixCapability,
|
||||
}
|
||||
impl MsixInfo {
|
||||
pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
&mut *self.virt_table_base.as_ptr().offset(k as isize)
|
||||
}
|
||||
pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry {
|
||||
assert!(k < self.capability.table_size() as usize);
|
||||
unsafe { self.table_entry_pointer_unchecked(k) }
|
||||
}
|
||||
pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 {
|
||||
&mut *self.virt_pba_base.as_ptr().offset(k as isize)
|
||||
}
|
||||
pub fn pba_pointer(&mut self, k: usize) -> &mut u64 {
|
||||
assert!(k < self.capability.table_size() as usize);
|
||||
unsafe { self.pba_pointer_unchecked(k) }
|
||||
}
|
||||
pub fn pba(&mut self, k: usize) -> bool {
|
||||
let byte = k / 64;
|
||||
let bit = k % 64;
|
||||
*self.pba_pointer(byte) & (1 << bit) != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Xhci {
|
||||
/// Gets descriptors, before the port state is initiated.
|
||||
async fn get_desc_raw<T>(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma<T>) -> Result<()> {
|
||||
let len = mem::size_of::<T>();
|
||||
|
||||
{
|
||||
let (cmd, cycle) = self.ring.next();
|
||||
let future = {
|
||||
let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?;
|
||||
let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe");
|
||||
|
||||
let (cmd, cycle) = ring.next();
|
||||
cmd.setup(
|
||||
usb::Setup::get_descriptor(kind, index, 0, len as u16),
|
||||
TransferKind::In,
|
||||
cycle,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let (cmd, cycle) = self.ring.next();
|
||||
let (cmd, cycle) = ring.next();
|
||||
cmd.data(desc.physical(), len as u16, true, cycle);
|
||||
}
|
||||
|
||||
{
|
||||
let (cmd, cycle) = self.ring.next();
|
||||
cmd.status(false, cycle);
|
||||
}
|
||||
let last_index = ring.next_index();
|
||||
let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle);
|
||||
cmd.status(0, true, true, false, false, cycle);
|
||||
|
||||
self.db.write(1);
|
||||
self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index])
|
||||
};
|
||||
|
||||
{
|
||||
let event = self.cmd.next_event();
|
||||
while event.data.read() == 0 {
|
||||
println!(" - Waiting for event");
|
||||
}
|
||||
}
|
||||
self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell());
|
||||
|
||||
self.int.erdp.write(self.cmd.erdp());
|
||||
let trbs = future.await;
|
||||
let event_trb = trbs.event_trb;
|
||||
let status_trb = trbs.src_trb.unwrap();
|
||||
|
||||
self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?;
|
||||
|
||||
self.event_handler_finished();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_device(&mut self) -> Result<usb::DeviceDescriptor> {
|
||||
async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result<usb::DeviceDescriptor> {
|
||||
let mut desc = Dma::<usb::DeviceDescriptor>::zeroed()?;
|
||||
self.get_desc(usb::DescriptorKind::Device, 0, &mut desc);
|
||||
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?;
|
||||
Ok(*desc)
|
||||
}
|
||||
|
||||
fn get_config(&mut self, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> {
|
||||
async fn fetch_config_desc(&self, port: usize, slot: u8, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> {
|
||||
let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?;
|
||||
self.get_desc(usb::DescriptorKind::Configuration, config, &mut desc);
|
||||
self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, &mut desc).await?;
|
||||
Ok(*desc)
|
||||
}
|
||||
|
||||
fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> {
|
||||
async fn fetch_bos_desc(&self, port: usize, slot: u8) -> Result<(usb::BosDescriptor, [u8; 4087])> {
|
||||
let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?;
|
||||
self.get_desc(usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc);
|
||||
self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc).await?;
|
||||
Ok(*desc)
|
||||
}
|
||||
|
||||
fn get_string(&mut self, index: u8) -> Result<String> {
|
||||
async fn fetch_string_desc(&self, port: usize, slot: u8, index: u8) -> Result<String> {
|
||||
let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?;
|
||||
self.get_desc(usb::DescriptorKind::String, index, &mut sdesc);
|
||||
self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc).await?;
|
||||
|
||||
let len = sdesc.0 as usize;
|
||||
if len > 2 {
|
||||
@@ -113,38 +162,54 @@ impl<'a> Device<'a> {
|
||||
}
|
||||
|
||||
pub struct Xhci {
|
||||
cap: &'static mut CapabilityRegs,
|
||||
op: &'static mut OperationalRegs,
|
||||
ports: &'static mut [Port],
|
||||
dbs: &'static mut [Doorbell],
|
||||
run: &'static mut RuntimeRegs,
|
||||
dev_ctx: DeviceContextList,
|
||||
cmd: CommandRing,
|
||||
// immutable
|
||||
cap: &'static CapabilityRegs,
|
||||
page_size: usize,
|
||||
|
||||
// XXX: It would be really useful to be able to mutably access individual elements of a slice,
|
||||
// without having to wrap every element in a lock (which wouldn't work since they're packed).
|
||||
op: Mutex<&'static mut OperationalRegs>,
|
||||
ports: Mutex<&'static mut [Port]>,
|
||||
dbs: Mutex<&'static mut [Doorbell]>,
|
||||
run: Mutex<&'static mut RuntimeRegs>,
|
||||
cmd: Mutex<Ring>,
|
||||
primary_event_ring: Mutex<EventRing>,
|
||||
|
||||
// immutable
|
||||
dev_ctx: DeviceContextList,
|
||||
scratchpad_buf_arr: Option<ScratchpadBufferArray>,
|
||||
|
||||
// used for the extended capabilities, and so far none of them are mutated, and thus no lock.
|
||||
base: *const u8,
|
||||
|
||||
handles: BTreeMap<usize, scheme::Handle>,
|
||||
next_handle: usize,
|
||||
port_states: BTreeMap<usize, PortState>,
|
||||
handles: CHashMap<usize, scheme::Handle>,
|
||||
next_handle: AtomicUsize,
|
||||
port_states: CHashMap<usize, PortState>,
|
||||
|
||||
// TODO: Is this the correct implementation? I mean, there will be a really limited number of
|
||||
// IRQs, if not just one, and since we probably wont use a thread pool scheduler like those of
|
||||
// async-std or tokio, one could possibly assume that the futures themselves won't have to push
|
||||
// all the wakers.
|
||||
// TODO: This should probably be a BTreeMap (or just a VecMap) of states for each IRQ number,
|
||||
// if more than one are used. I'm not sure if the XHCI interrupters actually use different
|
||||
// IRQs, but it would make sense in case the hub has both isochronous (which trigger interrupts
|
||||
// reapeatedly with some time in between), bulk, control, etc. I might be wrong though...
|
||||
irq_state: Arc<IrqState>,
|
||||
|
||||
drivers: BTreeMap<usize, process::Child>,
|
||||
drivers: CHashMap<usize, process::Child>,
|
||||
scheme_name: String,
|
||||
|
||||
interrupt_method: InterruptMethod,
|
||||
pcid_handle: Mutex<PcidServerHandle>,
|
||||
|
||||
irq_reactor: Mutex<Option<thread::JoinHandle<()>>>,
|
||||
|
||||
irq_reactor_sender: Sender<NewPendingTrb>,
|
||||
|
||||
// not used, but still stored so that the thread, when created, can get the channel without the
|
||||
// channel being in a mutex.
|
||||
irq_reactor_receiver: Receiver<NewPendingTrb>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Xhci {}
|
||||
unsafe impl Sync for Xhci {}
|
||||
|
||||
struct PortState {
|
||||
slot: u8,
|
||||
input_context: Dma<InputContext>,
|
||||
dev_desc: DevDesc,
|
||||
cfg_idx: Option<u8>,
|
||||
if_idx: Option<u8>,
|
||||
input_context: Mutex<Dma<InputContext>>,
|
||||
dev_desc: Option<DevDesc>,
|
||||
endpoint_states: BTreeMap<u8, EndpointState>,
|
||||
}
|
||||
|
||||
@@ -167,146 +232,209 @@ impl EndpointState {
|
||||
}
|
||||
|
||||
impl Xhci {
|
||||
pub fn new(scheme_name: String, address: usize) -> Result<Xhci> {
|
||||
pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PcidServerHandle) -> Result<Xhci> {
|
||||
let cap = unsafe { &mut *(address as *mut CapabilityRegs) };
|
||||
println!(" - CAP {:X}", address);
|
||||
debug!("CAP REGS BASE {:X}", address);
|
||||
|
||||
let page_size = {
|
||||
let memory_fd = syscall::open("memory:", O_RDONLY)?;
|
||||
let mut stat = syscall::data::StatVfs::default();
|
||||
syscall::fstatvfs(memory_fd, &mut stat)?;
|
||||
stat.f_bsize as usize
|
||||
};
|
||||
|
||||
let op_base = address + cap.len.read() as usize;
|
||||
let op = unsafe { &mut *(op_base as *mut OperationalRegs) };
|
||||
println!(" - OP {:X}", op_base);
|
||||
debug!("OP REGS BASE {:X}", op_base);
|
||||
|
||||
let (max_slots, max_ports) = {
|
||||
println!(" - Wait for ready");
|
||||
debug!("Waiting for xHC becoming ready.");
|
||||
// Wait until controller is ready
|
||||
while op.usb_sts.readf(1 << 11) {
|
||||
println!(" - Waiting for XHCI ready");
|
||||
trace!("Waiting for the xHC to be ready.");
|
||||
}
|
||||
|
||||
println!(" - Stop");
|
||||
debug!("Stopping the xHC");
|
||||
// Set run/stop to 0
|
||||
op.usb_cmd.writef(1, false);
|
||||
|
||||
println!(" - Wait for not running");
|
||||
debug!("Waiting for the xHC to stop.");
|
||||
// Wait until controller not running
|
||||
while !op.usb_sts.readf(1) {
|
||||
println!(" - Waiting for XHCI stopped");
|
||||
trace!("Waiting for the xHC to stop.");
|
||||
}
|
||||
|
||||
println!(" - Reset");
|
||||
debug!("Resetting the xHC.");
|
||||
op.usb_cmd.writef(1 << 1, true);
|
||||
while op.usb_sts.readf(1 << 1) {
|
||||
println!(" - Waiting for XHCI reset");
|
||||
trace!("Waiting for the xHC to reset.");
|
||||
}
|
||||
|
||||
println!(" - Read max slots");
|
||||
debug!("Reading max slots.");
|
||||
|
||||
let max_slots = cap.max_slots();
|
||||
let max_ports = cap.max_ports();
|
||||
|
||||
println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports);
|
||||
info!("xHC max slots: {}, max ports: {}", max_slots, max_ports);
|
||||
(max_slots, max_ports)
|
||||
};
|
||||
|
||||
let port_base = op_base + 0x400;
|
||||
let ports =
|
||||
unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) };
|
||||
println!(" - PORT {:X}", port_base);
|
||||
debug!("PORT BASE {:X}", port_base);
|
||||
|
||||
let db_base = address + cap.db_offset.read() as usize;
|
||||
let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut Doorbell, 256) };
|
||||
println!(" - DOORBELL {:X}", db_base);
|
||||
debug!("DOORBELL REGS BASE {:X}", db_base);
|
||||
|
||||
let run_base = address + cap.rts_offset.read() as usize;
|
||||
let run = unsafe { &mut *(run_base as *mut RuntimeRegs) };
|
||||
println!(" - RUNTIME {:X}", run_base);
|
||||
debug!("RUNTIME REGS BASE {:X}", run_base);
|
||||
|
||||
let mut xhci = Xhci {
|
||||
// Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the
|
||||
// DMA allocation (which is at least a 4k page).
|
||||
let entries_per_page = page_size / mem::size_of::<Trb>();
|
||||
let cmd = Ring::new(entries_per_page, true)?;
|
||||
|
||||
let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded();
|
||||
|
||||
let mut xhci = Self {
|
||||
base: address as *const u8,
|
||||
cap,
|
||||
op,
|
||||
ports,
|
||||
dbs,
|
||||
run,
|
||||
dev_ctx: DeviceContextList::new(max_slots)?,
|
||||
cmd: CommandRing::new()?,
|
||||
handles: BTreeMap::new(),
|
||||
next_handle: 0,
|
||||
port_states: BTreeMap::new(),
|
||||
|
||||
irq_state: Arc::new(IrqState {
|
||||
triggered: AtomicBool::new(false),
|
||||
wakers: Mutex::new(Vec::new()),
|
||||
}),
|
||||
drivers: BTreeMap::new(),
|
||||
cap,
|
||||
page_size,
|
||||
|
||||
op: Mutex::new(op),
|
||||
ports: Mutex::new(ports),
|
||||
dbs: Mutex::new(dbs),
|
||||
run: Mutex::new(run),
|
||||
|
||||
dev_ctx: DeviceContextList::new(max_slots)?,
|
||||
scratchpad_buf_arr: None, // initialized in init()
|
||||
|
||||
cmd: Mutex::new(cmd),
|
||||
primary_event_ring: Mutex::new(EventRing::new()?),
|
||||
handles: CHashMap::new(),
|
||||
next_handle: AtomicUsize::new(0),
|
||||
port_states: CHashMap::new(),
|
||||
|
||||
drivers: CHashMap::new(),
|
||||
scheme_name,
|
||||
|
||||
interrupt_method,
|
||||
pcid_handle: Mutex::new(pcid_handle),
|
||||
|
||||
irq_reactor: Mutex::new(None),
|
||||
irq_reactor_sender,
|
||||
irq_reactor_receiver,
|
||||
};
|
||||
|
||||
xhci.init(max_slots);
|
||||
xhci.init(max_slots)?;
|
||||
|
||||
Ok(xhci)
|
||||
}
|
||||
|
||||
pub fn init(&mut self, max_slots: u8) {
|
||||
pub fn init(&mut self, max_slots: u8) -> Result<()> {
|
||||
// Set enabled slots
|
||||
println!(" - Set enabled slots to {}", max_slots);
|
||||
self.op.config.write(max_slots as u32);
|
||||
println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF);
|
||||
debug!("Setting enabled slots to {}.", max_slots);
|
||||
self.op.get_mut().unwrap().config.write(max_slots as u32);
|
||||
debug!("Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF);
|
||||
|
||||
// Set device context address array pointer
|
||||
let dcbaap = self.dev_ctx.dcbaap();
|
||||
println!(" - Write DCBAAP: {:X}", dcbaap);
|
||||
self.op.dcbaap.write(dcbaap as u64);
|
||||
debug!("Writing DCBAAP: {:X}", dcbaap);
|
||||
self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64);
|
||||
|
||||
// Set command ring control register
|
||||
let crcr = self.cmd.crcr();
|
||||
println!(" - Write CRCR: {:X}", crcr);
|
||||
self.op.crcr.write(crcr as u64);
|
||||
let crcr = self.cmd.get_mut().unwrap().register();
|
||||
assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR");
|
||||
debug!("Writing CRCR: {:X}", crcr);
|
||||
self.op.get_mut().unwrap().crcr.write(crcr as u64);
|
||||
|
||||
// Set event ring segment table registers
|
||||
println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize);
|
||||
debug!("Interrupter 0: {:p}", self.run.get_mut().unwrap().ints.as_ptr());
|
||||
{
|
||||
let int = &mut self.run.get_mut().unwrap().ints[0];
|
||||
|
||||
let erstz = 1;
|
||||
println!(" - Write ERSTZ: {}", erstz);
|
||||
self.run.ints[0].erstsz.write(erstz);
|
||||
debug!("Writing ERSTZ: {}", erstz);
|
||||
int.erstsz.write(erstz);
|
||||
|
||||
let erdp = self.cmd.erdp();
|
||||
println!(" - Write ERDP: {:X}", erdp);
|
||||
self.run.ints[0].erdp.write(erdp as u64);
|
||||
let erdp = self.primary_event_ring.get_mut().unwrap().erdp();
|
||||
debug!("Writing ERDP: {:X}", erdp);
|
||||
int.erdp.write(erdp as u64 | (1 << 3));
|
||||
|
||||
let erstba = self.cmd.erstba();
|
||||
println!(" - Write ERSTBA: {:X}", erstba);
|
||||
self.run.ints[0].erstba.write(erstba as u64);
|
||||
let erstba = self.primary_event_ring.get_mut().unwrap().erstba();
|
||||
debug!("Writing ERSTBA: {:X}", erstba);
|
||||
int.erstba.write(erstba as u64);
|
||||
|
||||
debug!("Writing IMODC and IMODI: {} and {}", 0, 0);
|
||||
int.imod.write(0);
|
||||
|
||||
debug!("Enabling Primary Interrupter.");
|
||||
int.iman.writef(1 << 1 | 1, true);
|
||||
|
||||
println!(" - Enable interrupts");
|
||||
self.run.ints[0].iman.writef(1 << 1, true);
|
||||
}
|
||||
self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true);
|
||||
|
||||
// Setup the scratchpad buffers that are required for the xHC to function.
|
||||
self.setup_scratchpads()?;
|
||||
|
||||
// Set run/stop to 1
|
||||
println!(" - Start");
|
||||
self.op.usb_cmd.writef(1 | 1 << 2, true);
|
||||
info!("Starting xHC.");
|
||||
self.op.get_mut().unwrap().usb_cmd.writef(1, true);
|
||||
|
||||
// Wait until controller is running
|
||||
println!(" - Wait for running");
|
||||
while self.op.usb_sts.readf(1) {
|
||||
println!(" - Waiting for XHCI running");
|
||||
debug!("Waiting for start request to complete.");
|
||||
while self.op.get_mut().unwrap().usb_sts.readf(1) {
|
||||
trace!("Waiting for XHCI to report running status.");
|
||||
}
|
||||
|
||||
// Ring command doorbell
|
||||
println!(" - Ring doorbell");
|
||||
self.dbs[0].write(0);
|
||||
debug!("Ringing command doorbell.");
|
||||
self.dbs.get_mut().unwrap()[0].write(0);
|
||||
|
||||
println!(" - XHCI initialized");
|
||||
info!("XHCI initialized.");
|
||||
|
||||
if self.cap.cic() {
|
||||
self.op.get_mut().unwrap().set_cie(true);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result<u8> {
|
||||
pub fn setup_scratchpads(&mut self) -> Result<()> {
|
||||
let buf_count = self.cap.max_scratchpad_bufs();
|
||||
|
||||
if buf_count == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let scratchpad_buf_arr = ScratchpadBufferArray::new(self.page_size,buf_count)?;
|
||||
self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64;
|
||||
debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register());
|
||||
self.scratchpad_buf_arr = Some(scratchpad_buf_arr);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn enable_port_slot(&self, slot_ty: u8) -> Result<u8> {
|
||||
assert_eq!(slot_ty & 0x1F, slot_ty);
|
||||
|
||||
let cloned_event_trb =
|
||||
self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
|
||||
Ok(cloned_event_trb.event_slot())
|
||||
let (event_trb, command_trb) =
|
||||
self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await;
|
||||
|
||||
self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?;
|
||||
self.event_handler_finished();
|
||||
|
||||
Ok(event_trb.event_slot())
|
||||
}
|
||||
pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> {
|
||||
self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
|
||||
pub async fn disable_port_slot(&self, slot: u8) -> Result<()> {
|
||||
let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await;
|
||||
|
||||
self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?;
|
||||
self.event_handler_finished();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -314,49 +442,45 @@ impl Xhci {
|
||||
self.dev_ctx.contexts[slot].slot.state()
|
||||
}
|
||||
|
||||
pub fn probe(&mut self) -> Result<()> {
|
||||
for i in 0..self.ports.len() {
|
||||
pub async fn probe(&self) -> Result<()> {
|
||||
info!("XHCI capabilities: {:?}", self.capabilities_iter().collect::<Vec<_>>());
|
||||
|
||||
let port_count = { self.ports.lock().unwrap().len() };
|
||||
|
||||
for i in 0..port_count {
|
||||
let (data, state, speed, flags) = {
|
||||
let port = &self.ports[i];
|
||||
let port = &self.ports.lock().unwrap()[i];
|
||||
(port.read(), port.state(), port.speed(), port.flags())
|
||||
};
|
||||
println!(
|
||||
" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}",
|
||||
info!(
|
||||
"XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}",
|
||||
i, data, state, speed, flags
|
||||
);
|
||||
|
||||
if flags.contains(port::PortFlags::PORT_CCS) {
|
||||
//TODO: Link TRB when running to the end of the ring buffer
|
||||
|
||||
println!(" - Enable slot");
|
||||
|
||||
let slot_ty = self
|
||||
.supported_protocol(i as u8)
|
||||
.expect("Failed to find supported protocol information for port")
|
||||
.proto_slot_ty();
|
||||
let slot = self.enable_port_slot(slot_ty)?;
|
||||
|
||||
println!(" - Slot {}", slot);
|
||||
debug!("Slot type: {}", slot_ty);
|
||||
debug!("Enabling slot.");
|
||||
let slot = self.enable_port_slot(slot_ty).await?;
|
||||
|
||||
info!("Enabled port {}, which the xHC mapped to {}", i, slot);
|
||||
|
||||
let mut input = Dma::<InputContext>::zeroed()?;
|
||||
let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed)?;
|
||||
let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?;
|
||||
info!("Addressed device");
|
||||
|
||||
let dev_desc = Self::get_dev_desc_raw(
|
||||
&mut self.ports,
|
||||
&mut self.run,
|
||||
&mut self.cmd,
|
||||
&mut self.dbs,
|
||||
i,
|
||||
slot,
|
||||
&mut ring,
|
||||
)?;
|
||||
|
||||
self.update_default_control_pipe(&mut input, slot, &dev_desc)?;
|
||||
// TODO: Should the descriptors be cached in PortState, or refetched?
|
||||
|
||||
let mut port_state = PortState {
|
||||
slot,
|
||||
input_context: input,
|
||||
dev_desc,
|
||||
input_context: Mutex::new(input),
|
||||
dev_desc: None,
|
||||
cfg_idx: None,
|
||||
if_idx: None,
|
||||
endpoint_states: std::iter::once((
|
||||
0,
|
||||
EndpointState {
|
||||
@@ -366,25 +490,33 @@ impl Xhci {
|
||||
))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
};
|
||||
self.port_states.insert(i, port_state);
|
||||
|
||||
if self.cap.cic() {
|
||||
self.op.set_cie(true);
|
||||
let dev_desc = self.get_desc(i, slot).await?;
|
||||
self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc);
|
||||
|
||||
{
|
||||
let mut port_state = self.port_states.get_mut(&i).unwrap();
|
||||
|
||||
let mut input = port_state.input_context.lock().unwrap();
|
||||
let dev_desc = port_state.dev_desc.as_ref().unwrap();
|
||||
|
||||
self.update_default_control_pipe(&mut *input, slot, dev_desc).await?;
|
||||
}
|
||||
|
||||
/*match self.spawn_drivers(i, &mut port_state) {
|
||||
Ok(()) => (),
|
||||
Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err),
|
||||
Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err),
|
||||
}*/
|
||||
|
||||
self.port_states.insert(i, port_state);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_default_control_pipe(
|
||||
&mut self,
|
||||
pub async fn update_default_control_pipe(
|
||||
&self,
|
||||
input_context: &mut Dma<InputContext>,
|
||||
slot_id: u8,
|
||||
dev_desc: &DevDesc,
|
||||
@@ -403,14 +535,18 @@ impl Xhci {
|
||||
b |= (new_max_packet_size) << 16;
|
||||
endp_ctx.b.write(b);
|
||||
|
||||
self.execute_command("EVALUATE_CONTEXT", |trb, cycle| {
|
||||
let (event_trb, command_trb) = self.execute_command(|trb, cycle| {
|
||||
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
|
||||
})?;
|
||||
}).await;
|
||||
|
||||
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?;
|
||||
self.event_handler_finished();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn address_device(
|
||||
&mut self,
|
||||
pub async fn address_device(
|
||||
&self,
|
||||
input_context: &mut Dma<InputContext>,
|
||||
i: usize,
|
||||
slot_ty: u8,
|
||||
@@ -498,39 +634,65 @@ impl Xhci {
|
||||
|
||||
let input_context_physical = input_context.physical();
|
||||
|
||||
self.execute_command("ADDRESS_DEVICE", |trb, cycle| {
|
||||
let (event_trb, _) = self.execute_command(|trb, cycle| {
|
||||
trb.address_device(slot, input_context_physical, false, cycle)
|
||||
})
|
||||
.expect("ADDRESS_DEVICE failed");
|
||||
}).await;
|
||||
|
||||
if event_trb.completion_code() != TrbCompletionCode::Success as u8 {
|
||||
error!("Failed to address device at slot {} (port {})", slot, i);
|
||||
self.event_handler_finished();
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
self.event_handler_finished();
|
||||
|
||||
Ok(ring)
|
||||
}
|
||||
|
||||
pub fn uses_msi(&self) -> bool {
|
||||
if let InterruptMethod::Msi = self.interrupt_method { true } else { false }
|
||||
}
|
||||
pub fn uses_msix(&self) -> bool {
|
||||
if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false }
|
||||
}
|
||||
// TODO: Perhaps use an rwlock?
|
||||
pub fn msix_info(&self) -> Option<MutexGuard<'_, MsixInfo>> {
|
||||
match self.interrupt_method {
|
||||
InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn msix_info_mut(&self) -> Option<MutexGuard<'_, MsixInfo>> {
|
||||
match self.interrupt_method {
|
||||
InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trigger_irq(&mut self) -> bool {
|
||||
// Read the Interrupter Pending bit.
|
||||
if self.run.ints[0].iman.readf(1) {
|
||||
//println!("XHCI Interrupt");
|
||||
/// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always
|
||||
/// true when using MSI/MSI-X.
|
||||
pub fn received_irq(&self) -> bool {
|
||||
let mut runtime_regs = self.run.lock().unwrap();
|
||||
|
||||
// If set, set it back to zero, so that new interrupts can be triggered.
|
||||
// FIXME: MSI and MSI-X systems
|
||||
self.run.ints[0].iman.writef(1, true);
|
||||
|
||||
// Wake all futures awaiting the IRQ.
|
||||
for waker in self.irq_state.wakers.lock().unwrap().drain(..) {
|
||||
waker.wake();
|
||||
}
|
||||
if self.uses_msi() || self.uses_msix() {
|
||||
// Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit
|
||||
// doesn't have to be touched.
|
||||
trace!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3));
|
||||
true
|
||||
} else if runtime_regs.ints[0].iman.readf(1) {
|
||||
trace!("Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3));
|
||||
// If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is
|
||||
// a special register to specify whether the IRQ actually came from the xHC.
|
||||
runtime_regs.ints[0].iman.writef(1, true);
|
||||
|
||||
// The interrupt came from the xHC.
|
||||
true
|
||||
} else {
|
||||
// The interrupt came from a different device.
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
pub(crate) fn irq(&self) -> IrqFuture {
|
||||
IrqFuture {
|
||||
state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)),
|
||||
}
|
||||
}
|
||||
fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> {
|
||||
fn spawn_drivers(&self, port: usize, ps: &mut PortState) -> Result<()> {
|
||||
// TODO: There should probably be a way to select alternate interfaces, and not just the
|
||||
// first one.
|
||||
// TODO: Now that there are some good error crates, I don't think errno.h error codes are
|
||||
@@ -538,12 +700,14 @@ impl Xhci {
|
||||
|
||||
let ifdesc = &ps
|
||||
.dev_desc
|
||||
.as_ref().unwrap()
|
||||
.config_descs
|
||||
.first()
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.interface_descs
|
||||
.first()
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG;
|
||||
|
||||
if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| {
|
||||
@@ -553,7 +717,7 @@ impl Xhci {
|
||||
.map(|subclass| subclass == ifdesc.sub_class)
|
||||
.unwrap_or(true)
|
||||
}) {
|
||||
println!("Loading driver \"{}\"", driver.name);
|
||||
info!("Loading subdriver\"{}\"", driver.name);
|
||||
let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?;
|
||||
|
||||
let if_proto = ifdesc.protocol;
|
||||
@@ -680,6 +844,18 @@ impl Xhci {
|
||||
.find(|speed| speed.psiv() == psiv)
|
||||
}
|
||||
}
|
||||
pub fn start_irq_reactor(hci: &Arc<Xhci>, irq_file: Option<File>) {
|
||||
let receiver = hci.irq_reactor_receiver.clone();
|
||||
let hci_clone = Arc::clone(&hci);
|
||||
|
||||
debug!("About to start IRQ reactor");
|
||||
|
||||
*hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || {
|
||||
info!("Started IRQ reactor thread");
|
||||
IrqReactor::new(hci_clone, receiver, irq_file).run()
|
||||
}));
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DriverConfig {
|
||||
name: String,
|
||||
@@ -707,44 +883,3 @@ lazy_static! {
|
||||
toml::from_slice::<DriversConfig>(TOML).expect("Failed to parse internally embedded config file")
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) struct IrqFuture {
|
||||
state: IrqFutureState,
|
||||
}
|
||||
|
||||
struct IrqState {
|
||||
triggered: AtomicBool,
|
||||
// TODO: Perhaps a channel?
|
||||
wakers: Mutex<Vec<task::Waker>>,
|
||||
}
|
||||
|
||||
enum IrqFutureState {
|
||||
Pending(Weak<IrqState>),
|
||||
Finished,
|
||||
}
|
||||
|
||||
impl std::future::Future for IrqFuture {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
|
||||
match &mut this.state {
|
||||
// TODO: Ordering?
|
||||
IrqFutureState::Pending(state_weak) => {
|
||||
let state = state_weak.upgrade().expect(
|
||||
"IRQ futures keep getting polled even after the driver has been deinitialized",
|
||||
);
|
||||
|
||||
if state.triggered.load(atomic::Ordering::SeqCst) {
|
||||
this.state = IrqFutureState::Finished;
|
||||
task::Poll::Ready(())
|
||||
} else {
|
||||
state.wakers.lock().unwrap().push(context.waker().clone());
|
||||
task::Poll::Pending
|
||||
}
|
||||
}
|
||||
IrqFutureState::Finished => panic!("polling finished future"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+56
-1
@@ -1,3 +1,5 @@
|
||||
use std::mem;
|
||||
|
||||
use syscall::error::Result;
|
||||
use syscall::io::Dma;
|
||||
|
||||
@@ -26,7 +28,7 @@ impl Ring {
|
||||
addr as u64 | self.cycle as u64
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> (&mut Trb, bool) {
|
||||
pub fn next_index(&mut self) -> usize {
|
||||
let mut i;
|
||||
loop {
|
||||
i = self.i;
|
||||
@@ -45,7 +47,11 @@ impl Ring {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> (&mut Trb, bool) {
|
||||
let i = self.next_index();
|
||||
(&mut self.trbs[i], self.cycle)
|
||||
}
|
||||
/// Endless iterator that iterates through the ring items, over and over again. The iterator
|
||||
@@ -53,6 +59,55 @@ impl Ring {
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Trb> + '_ {
|
||||
Iter { ring: self, i: self.i }
|
||||
}
|
||||
/// Takes a physical address and returns the index into this ring, that the index represents.
|
||||
/// Returns `None` if the address is outside the bounds of this ring.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB.
|
||||
// TODO: Use usize instead of u64.
|
||||
pub fn phys_addr_to_index(&self, paddr: u64) -> Option<usize> {
|
||||
let base = self.trbs.physical();
|
||||
let offset = paddr.checked_sub(base as u64)? as usize;
|
||||
|
||||
assert_eq!(offset % mem::size_of::<Trb>(), 0, "unaligned TRB physical address");
|
||||
|
||||
let index = offset / mem::size_of::<Trb>();
|
||||
|
||||
if index > self.trbs.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(index)
|
||||
}
|
||||
pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> {
|
||||
Some(&self.trbs[self.phys_addr_to_index(paddr)?])
|
||||
}
|
||||
pub fn phys_addr_to_entry_mut(&mut self, paddr: u64) -> Option<&mut Trb> {
|
||||
let index = self.phys_addr_to_index(paddr)?;
|
||||
Some(&mut self.trbs[index])
|
||||
}
|
||||
pub fn phys_addr_to_entry(&self, paddr: u64) -> Option<Trb> {
|
||||
Some(self.trbs[self.phys_addr_to_index(paddr)?].clone())
|
||||
}
|
||||
pub(crate) fn start_virt_addr(&self) -> *const Trb {
|
||||
self.trbs.as_ptr()
|
||||
}
|
||||
pub(crate) fn end_virt_addr(&self) -> *const Trb {
|
||||
unsafe { self.start_virt_addr().offset(self.trbs.len() as isize) }
|
||||
}
|
||||
pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 {
|
||||
let trb_virt_pointer = trb as *const Trb;
|
||||
let trbs_base_virt_pointer = self.trbs.as_ptr();
|
||||
|
||||
if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::<Trb>() {
|
||||
panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb);
|
||||
}
|
||||
let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64;
|
||||
|
||||
let trbs_base_phys_ptr = self.trbs.physical() as u64;
|
||||
let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base;
|
||||
trb_phys_ptr
|
||||
}
|
||||
/*
|
||||
/// Endless mutable iterator that iterates through the ring items, over and over again. The
|
||||
/// iterator doesn't enqueue or dequeue anything, but the trbs are mutably borrowed.
|
||||
|
||||
+606
-535
File diff suppressed because it is too large
Load Diff
+84
-6
@@ -5,6 +5,7 @@ use syscall::io::{Io, Mmio};
|
||||
use super::context::StreamContextType;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum TrbType {
|
||||
Reserved,
|
||||
/* Transfer */
|
||||
@@ -33,8 +34,8 @@ pub enum TrbType {
|
||||
ForceHeader,
|
||||
NoOpCmd,
|
||||
/* Reserved */
|
||||
Rsv24,
|
||||
Rsv25,
|
||||
GetExtendedProperty,
|
||||
SetExtendedProperty,
|
||||
Rsv26,
|
||||
Rsv27,
|
||||
Rsv28,
|
||||
@@ -54,6 +55,7 @@ pub enum TrbType {
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum TrbCompletionCode {
|
||||
Invalid,
|
||||
Success,
|
||||
@@ -157,6 +159,34 @@ impl Trb {
|
||||
pub fn completion_param(&self) -> u32 {
|
||||
self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK
|
||||
}
|
||||
fn has_completion_trb_pointer(&self) -> bool {
|
||||
if self.completion_code() == TrbCompletionCode::RingUnderrun as u8 || self.completion_code() == TrbCompletionCode::RingOverrun as u8 {
|
||||
false
|
||||
} else if self.completion_code() == TrbCompletionCode::VfEventRingFull as u8 {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
pub fn completion_trb_pointer(&self) -> Option<u64> {
|
||||
debug_assert_eq!(self.trb_type(), TrbType::CommandCompletion as u8);
|
||||
|
||||
if self.has_completion_trb_pointer() {
|
||||
Some(self.data.read())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn transfer_event_trb_pointer(&self) -> Option<u64> {
|
||||
debug_assert_eq!(self.trb_type(), TrbType::Transfer as u8);
|
||||
|
||||
if self.has_completion_trb_pointer() {
|
||||
Some(self.data.read())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_slot(&self) -> u8 {
|
||||
(self.control.read() >> 24) as u8
|
||||
}
|
||||
@@ -203,6 +233,15 @@ impl Trb {
|
||||
| (cycle as u32),
|
||||
);
|
||||
}
|
||||
pub fn disable_slot(&mut self, slot: u8, cycle: bool) {
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
(u32::from(slot) << 24)
|
||||
| ((TrbType::DisableSlot as u32) << 10)
|
||||
| u32::from(cycle)
|
||||
);
|
||||
}
|
||||
|
||||
pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) {
|
||||
assert_eq!(
|
||||
@@ -335,13 +374,15 @@ impl Trb {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn status(&mut self, input: bool, cycle: bool) {
|
||||
pub fn status(&mut self, interrupter: u16, input: bool, ioc: bool, ch: bool, ent: bool, cycle: bool) {
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
((input as u32) << 16)
|
||||
u32::from(interrupter) << 22,
|
||||
(u32::from(input) << 16)
|
||||
| ((TrbType::StatusStage as u32) << 10)
|
||||
| (1 << 5)
|
||||
| (u32::from(ioc) << 5)
|
||||
| (u32::from(ch) << 4)
|
||||
| (u32::from(ent) << 1)
|
||||
| (cycle as u32),
|
||||
);
|
||||
}
|
||||
@@ -374,6 +415,43 @@ impl Trb {
|
||||
| ((TrbType::Normal as u32) << 10),
|
||||
)
|
||||
}
|
||||
pub fn is_command_trb(&self) -> bool {
|
||||
let valid_trb_types = [
|
||||
TrbType::NoOpCmd as u8,
|
||||
TrbType::EnableSlot as u8,
|
||||
TrbType::DisableSlot as u8,
|
||||
TrbType::AddressDevice as u8,
|
||||
TrbType::ConfigureEndpoint as u8,
|
||||
TrbType::EvaluateContext as u8,
|
||||
TrbType::ResetEndpoint as u8,
|
||||
TrbType::StopEndpoint as u8,
|
||||
TrbType::SetTrDequeuePointer as u8,
|
||||
TrbType::ResetDevice as u8,
|
||||
TrbType::ForceEvent as u8,
|
||||
TrbType::NegotiateBandwidth as u8,
|
||||
TrbType::SetLatencyToleranceValue as u8,
|
||||
TrbType::GetPortBandwidth as u8,
|
||||
TrbType::ForceHeader as u8,
|
||||
TrbType::GetExtendedProperty as u8,
|
||||
TrbType::SetExtendedProperty as u8,
|
||||
];
|
||||
valid_trb_types.contains(&self.trb_type())
|
||||
}
|
||||
pub fn is_transfer_trb(&self) -> bool {
|
||||
// XXX: Unfortunately, the only way to use match statements with integer constants, is to
|
||||
// precast them into valid enum values, which either requires a derive macro such as
|
||||
// num_traits's #[derive(FromPrimitive)], or manually writing the reverse match statement
|
||||
// first.
|
||||
let valid_trb_types = [
|
||||
TrbType::Normal as u8,
|
||||
TrbType::SetupStage as u8,
|
||||
TrbType::DataStage as u8,
|
||||
TrbType::StatusStage as u8,
|
||||
TrbType::Isoch as u8,
|
||||
TrbType::NoOp as u8,
|
||||
];
|
||||
valid_trb_types.contains(&self.trb_type())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Trb {
|
||||
|
||||
Reference in New Issue
Block a user