├── hwd ├── .gitignore ├── Cargo.toml └── src │ ├── backend │ ├── mod.rs │ ├── legacy.rs │ └── devicetree.rs │ └── main.rs ├── pcid ├── .gitignore ├── src │ ├── lib.rs │ ├── driver_interface │ │ ├── cap.rs │ │ ├── id.rs │ │ ├── bar.rs │ │ └── config.rs │ └── cfg_access │ │ └── fallback.rs └── Cargo.toml ├── input ├── ps2d │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── vm.rs │ │ └── scheme.rs └── usbhidd │ ├── .gitignore │ ├── Cargo.toml │ └── src │ └── reqs.rs ├── usb ├── usbctl │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── xhcid │ ├── .gitignore │ ├── config.toml │ ├── src │ │ ├── xhci │ │ │ ├── doorbell.rs │ │ │ ├── runtime.rs │ │ │ ├── event.rs │ │ │ ├── port.rs │ │ │ └── operational.rs │ │ ├── usb │ │ │ ├── interface.rs │ │ │ ├── config.rs │ │ │ ├── endpoint.rs │ │ │ └── mod.rs │ │ └── lib.rs │ ├── drivers.toml │ └── Cargo.toml └── usbhubd │ ├── .gitignore │ └── Cargo.toml ├── storage ├── ahcid │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── ahci │ │ └── mod.rs │ │ └── main.rs ├── ided │ ├── .gitignore │ └── Cargo.toml ├── nvmed │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── nvme │ │ ├── executor.rs │ │ ├── queues.rs │ │ └── cmd.rs ├── usbscsid │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── protocol │ │ └── mod.rs │ │ └── scsi │ │ └── opcodes.rs ├── partitionlib │ ├── src │ │ ├── lib.rs │ │ ├── mbr.rs │ │ └── partition.rs │ ├── resources │ │ ├── disk.img │ │ └── disk_mbr.img │ ├── Cargo.toml │ └── tests │ │ └── test.rs ├── lived │ └── Cargo.toml ├── driver-block │ └── Cargo.toml ├── bcm2835-sdhcid │ ├── Cargo.toml │ └── src │ │ └── main.rs └── virtio-blkd │ ├── Cargo.toml │ └── src │ └── scheme.rs ├── graphics ├── graphics-ipc │ ├── src │ │ ├── lib.rs │ │ ├── common.rs │ │ └── v1.rs │ └── Cargo.toml ├── bgad │ ├── config.toml │ ├── Cargo.toml │ └── src │ │ ├── bga.rs │ │ ├── main.rs │ │ └── scheme.rs ├── console-draw │ └── Cargo.toml ├── driver-graphics │ └── Cargo.toml ├── fbbootlogd │ └── Cargo.toml ├── vesad │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── fbcond │ ├── Cargo.toml │ └── src │ │ └── display.rs └── virtio-gpud │ └── Cargo.toml ├── rust-toolchain.toml ├── audio ├── ac97d │ ├── config.toml │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── ihdad │ ├── config.toml │ ├── Cargo.toml │ └── src │ │ └── hda │ │ ├── mod.rs │ │ └── node.rs └── sb16d │ ├── Cargo.toml │ └── src │ └── main.rs ├── net ├── rtl8139d │ ├── config.toml │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── rtl8168d │ ├── config.toml │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── virtio-netd │ ├── config.toml │ ├── Cargo.toml │ └── src │ │ ├── scheme.rs │ │ └── main.rs ├── e1000d │ ├── config.toml │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── driver-network │ └── Cargo.toml ├── alxd │ └── Cargo.toml └── ixgbed │ ├── Cargo.toml │ ├── config.toml │ ├── README.md │ └── src │ └── main.rs ├── vboxd ├── config.toml ├── Cargo.toml └── src │ └── bga.rs ├── fmt.sh ├── rtcd ├── Cargo.toml └── src │ ├── main.rs │ └── x86.rs ├── virtio-core ├── src │ ├── arch │ │ ├── riscv64.rs │ │ ├── aarch64.rs │ │ └── x86.rs │ ├── lib.rs │ ├── utils.rs │ └── spec │ │ └── mod.rs └── Cargo.toml ├── executor └── Cargo.toml ├── .gitignore ├── .gitlab-ci.yml ├── common ├── Cargo.toml └── src │ ├── timeout.rs │ ├── logger.rs │ ├── io │ └── pio.rs │ └── io.rs ├── inputd └── Cargo.toml ├── pcid-spawner ├── Cargo.toml └── src │ └── main.rs ├── amlserde └── Cargo.toml ├── acpid ├── Cargo.toml └── src │ └── acpi │ └── dmar │ └── drhd.rs ├── initfs.toml ├── .gitlab ├── merge_request_templates │ └── Merge_request_template.md └── issue_templates │ └── Issue_template.md ├── LICENSE ├── Cargo.toml └── COMMUNITY-HW.md /hwd/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /pcid/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /input/ps2d/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /usb/usbctl/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /usb/xhcid/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /input/usbhidd/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /storage/ahcid/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /storage/ided/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /storage/nvmed/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /usb/usbhubd/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /storage/usbscsid/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /graphics/graphics-ipc/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | pub mod v1; 3 | pub mod v2; 4 | -------------------------------------------------------------------------------- /storage/partitionlib/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod mbr; 2 | mod partition; 3 | pub use self::partition::*; 4 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2025-10-03" 3 | components = ["rust-src"] 4 | -------------------------------------------------------------------------------- /pcid/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Interface to `pcid`. 2 | 3 | mod driver_interface; 4 | pub use driver_interface::*; 5 | -------------------------------------------------------------------------------- /audio/ac97d/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "AC97 Audio" 3 | class = 0x04 4 | subclass = 0x01 5 | command = ["ac97d"] 6 | -------------------------------------------------------------------------------- /audio/ihdad/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "Intel HD Audio" 3 | class = 0x04 4 | subclass = 0x03 5 | command = ["ihdad"] 6 | -------------------------------------------------------------------------------- /storage/partitionlib/resources/disk.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redox-os/drivers/HEAD/storage/partitionlib/resources/disk.img -------------------------------------------------------------------------------- /storage/partitionlib/resources/disk_mbr.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redox-os/drivers/HEAD/storage/partitionlib/resources/disk_mbr.img -------------------------------------------------------------------------------- /net/rtl8139d/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "RTL8139 NIC" 3 | class = 0x02 4 | ids = { 0x10ec = [0x8139] } 5 | command = ["rtl8139d"] 6 | -------------------------------------------------------------------------------- /net/rtl8168d/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "RTL8168 NIC" 3 | class = 0x02 4 | ids = { 0x10ec = [0x8168, 0x8169] } 5 | command = ["rtl8168d"] 6 | -------------------------------------------------------------------------------- /vboxd/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "VirtualBox Guest Device" 3 | class = 0x08 4 | vendor = 0x80EE 5 | device = 0xCAFE 6 | command = ["vboxd"] 7 | -------------------------------------------------------------------------------- /graphics/bgad/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "QEMU Graphics Array" 3 | class = 0x03 4 | vendor = 0x1234 5 | device = 0x1111 6 | command = ["bgad"] 7 | -------------------------------------------------------------------------------- /net/virtio-netd/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "virtio-net" 3 | class = 0x02 4 | vendor = 0x1AF4 5 | device = 0x1000 6 | command = ["virtio-netd"] 7 | -------------------------------------------------------------------------------- /usb/xhcid/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "XHCI" 3 | class = 0x0C 4 | subclass = 0x03 5 | interface = 0x30 6 | command = ["xhcid"] 7 | use_channel = true 8 | -------------------------------------------------------------------------------- /net/e1000d/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "E1000 NIC" 3 | class = 0x02 4 | ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x109a, 0x1503] } 5 | command = ["e1000d"] 6 | -------------------------------------------------------------------------------- /fmt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | printf "\e[1;32mFormatting\e[0m $dir\n" 6 | if [[ "$CHECK_ONLY" -eq "1" ]]; then 7 | cargo fmt --all --check 8 | else 9 | cargo fmt --all 10 | fi 11 | -------------------------------------------------------------------------------- /graphics/graphics-ipc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "graphics-ipc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | log = "0.4" 8 | libredox = "0.1.3" 9 | 10 | common = { path = "../../common" } 11 | -------------------------------------------------------------------------------- /rtcd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rtcd" 3 | version = "0.1.0" 4 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 5 | edition = "2018" 6 | license = "MIT" 7 | 8 | 9 | [dependencies] 10 | anyhow = "1" 11 | 12 | common = { path = "../common" } 13 | -------------------------------------------------------------------------------- /net/driver-network/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver-network" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | libredox = "0.1.3" 8 | redox-daemon = "0.1" 9 | redox-scheme = "0.4" 10 | redox_syscall = { version = "0.5", features = ["std"] } 11 | -------------------------------------------------------------------------------- /graphics/console-draw/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "console-draw" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | orbclient = "0.3.27" 8 | ransid = "0.4" 9 | 10 | graphics-ipc = { path = "../graphics-ipc" } 11 | 12 | [features] 13 | default = [] 14 | -------------------------------------------------------------------------------- /hwd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hwd" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | fdt = "0.1.5" 8 | log = "0.4" 9 | redox-daemon = "0.1" 10 | ron = "0.8.1" 11 | 12 | amlserde = { path = "../amlserde" } 13 | common = { path = "../common" } 14 | -------------------------------------------------------------------------------- /virtio-core/src/arch/riscv64.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | use pcid_interface::*; 4 | 5 | use crate::{transport::Error, Device}; 6 | 7 | pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { 8 | unimplemented!("virtio_core: enable_msix") 9 | } 10 | -------------------------------------------------------------------------------- /virtio-core/src/arch/aarch64.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | use pcid_interface::*; 4 | 5 | use crate::{transport::Error, Device}; 6 | 7 | pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { 8 | unimplemented!("virtio_core: aarch64 enable_msix") 9 | } 10 | -------------------------------------------------------------------------------- /net/alxd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alxd" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | bitflags = "2" 8 | redox_event = "0.4.1" 9 | redox_syscall = "0.5" 10 | redox-daemon = "0.1" 11 | 12 | common = { path = "../../common" } 13 | libredox = "0.1.3" 14 | redox-scheme = "0.8.2" 15 | -------------------------------------------------------------------------------- /executor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "executor" 3 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 4 | version = "0.1.0" 5 | edition = "2021" 6 | license = "MIT" 7 | description = "Async framework for queue-based HW interfaces" 8 | 9 | [dependencies] 10 | log = "0.4" 11 | redox_event = "0.4.1" 12 | slab = "0.4.9" 13 | -------------------------------------------------------------------------------- /vboxd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vboxd" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | libredox = "0.1.3" 8 | orbclient = "0.3.47" 9 | redox_event = "0.4.1" 10 | redox_syscall = "0.5" 11 | redox-daemon = "0.1" 12 | 13 | common = { path = "../common" } 14 | pcid = { path = "../pcid" } 15 | -------------------------------------------------------------------------------- /usb/xhcid/src/xhci/doorbell.rs: -------------------------------------------------------------------------------- 1 | use common::io::{Io, Mmio}; 2 | 3 | #[repr(C, packed)] 4 | pub struct Doorbell(Mmio); 5 | 6 | impl Doorbell { 7 | pub fn read(&self) -> u32 { 8 | self.0.read() 9 | } 10 | 11 | pub fn write(&mut self, data: u32) { 12 | self.0.write(data); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /usb/usbctl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "usbctl" 3 | version = "0.1.0" 4 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | clap = "2.33" 11 | xhcid = { path = "../xhcid" } 12 | -------------------------------------------------------------------------------- /audio/sb16d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sb16d" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bitflags = "2" 8 | common = { path = "../../common" } 9 | libredox = "0.1.3" 10 | log = "0.4" 11 | redox-daemon = "0.1" 12 | redox_event = "0.4.1" 13 | redox_syscall = "0.5" 14 | spin = "0.9" 15 | redox-scheme = "0.8.2" 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | # Local settings folder for Visual Studio Code 4 | .vscode/ 5 | # Local settings folder for Jetbrains products (RustRover, IntelliJ, CLion) 6 | .idea/ 7 | # Local settings folder for Visual Studio Professional 8 | .vs/ 9 | # Local settings folder for the devcontainer extension that most IDEs support. 10 | .devcontainer/ 11 | -------------------------------------------------------------------------------- /storage/partitionlib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "partitionlib" 3 | version = "0.1.0" 4 | authors = ["Deepak Sirone "] 5 | edition = "2021" 6 | license = "MIT" 7 | 8 | [dependencies] 9 | gpt = { version = "3.0.1" } 10 | scroll = { version = "0.10", features = ["derive"] } 11 | uuid = { version = "1.0", features = ["v4"] } 12 | -------------------------------------------------------------------------------- /graphics/driver-graphics/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver-graphics" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | log = "0.4" 8 | redox-scheme = "0.6.2" 9 | redox_syscall = "0.5" 10 | libredox = "0.1.3" 11 | 12 | common = { path = "../../common" } 13 | graphics-ipc = { path = "../graphics-ipc" } 14 | inputd = { path = "../../inputd" } 15 | -------------------------------------------------------------------------------- /net/ixgbed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ixgbed" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bitflags = "2" 8 | libredox = "0.1.3" 9 | redox_event = "0.4.1" 10 | redox_syscall = "0.5" 11 | redox-daemon = "0.1" 12 | 13 | common = { path = "../../common" } 14 | driver-network = { path = "../driver-network" } 15 | pcid = { path = "../../pcid" } 16 | -------------------------------------------------------------------------------- /usb/usbhubd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "usbhubd" 3 | version = "0.1.0" 4 | edition = "2018" 5 | license = "MIT" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | log = "0.4" 11 | redox_syscall = "0.5" 12 | xhcid = { path = "../xhcid" } 13 | 14 | common = { path = "../../common" } 15 | -------------------------------------------------------------------------------- /audio/ac97d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ac97d" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bitflags = "1" 8 | common = { path = "../../common" } 9 | libredox = "0.1.3" 10 | log = "0.4" 11 | redox-daemon = "0.1" 12 | redox_event = "0.4.1" 13 | redox_syscall = "0.5" 14 | spin = "0.9" 15 | 16 | pcid = { path = "../../pcid" } 17 | redox-scheme = "0.8.2" 18 | -------------------------------------------------------------------------------- /audio/ihdad/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ihdad" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bitflags = "2" 8 | libredox = "0.1.3" 9 | log = "0.4" 10 | redox-daemon = "0.1" 11 | redox_event = "0.4.1" 12 | redox_syscall = "0.5" 13 | spin = "0.9" 14 | 15 | common = { path = "../../common" } 16 | pcid = { path = "../../pcid" } 17 | redox-scheme = "0.8.2" 18 | -------------------------------------------------------------------------------- /graphics/bgad/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bgad" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | orbclient = "0.3.47" 8 | log = "0.4" 9 | redox-daemon = "0.1" 10 | redox-scheme = "0.6.2" 11 | redox_syscall = "0.5" 12 | 13 | common = { path = "../../common" } 14 | inputd = { path = "../../inputd" } 15 | pcid = { path = "../../pcid" } 16 | libredox = "0.1.3" 17 | -------------------------------------------------------------------------------- /hwd/src/backend/mod.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | mod acpi; 4 | mod devicetree; 5 | mod legacy; 6 | 7 | pub use self::{acpi::AcpiBackend, devicetree::DeviceTreeBackend, legacy::LegacyBackend}; 8 | 9 | pub trait Backend { 10 | fn new() -> Result> 11 | where 12 | Self: Sized; 13 | fn probe(&mut self) -> Result<(), Box>; 14 | } 15 | -------------------------------------------------------------------------------- /net/e1000d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "e1000d" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | bitflags = "2" 8 | log = "0.4" 9 | redox-daemon = "0.1.2" 10 | libredox = "0.1.3" 11 | redox_event = "0.4.1" 12 | redox_syscall = "0.5" 13 | 14 | common = { path = "../../common" } 15 | driver-network = { path = "../driver-network" } 16 | pcid = { path = "../../pcid" } 17 | -------------------------------------------------------------------------------- /storage/ided/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ided" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | common = { path = "../../common" } 8 | driver-block = { path = "../driver-block" } 9 | libredox = "0.1.3" 10 | log = "0.4" 11 | pcid = { path = "../../pcid" } 12 | redox-daemon = "0.1" 13 | redox_syscall = { version = "0.5", features = ["std"] } 14 | redox_event = "0.4" 15 | -------------------------------------------------------------------------------- /input/ps2d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ps2d" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | bitflags = "1" 8 | log = "0.4" 9 | orbclient = "0.3.27" 10 | redox_event = "0.4.1" 11 | redox_syscall = "0.5.10" 12 | redox-daemon = "0.1" 13 | redox-scheme = "0.6.2" 14 | libredox = "0.1.3" 15 | 16 | common = { path = "../../common" } 17 | inputd = { path = "../../inputd" } 18 | -------------------------------------------------------------------------------- /net/rtl8139d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rtl8139d" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | bitflags = "2" 8 | libredox = "0.1.3" 9 | log = "0.4" 10 | redox_event = "0.4.1" 11 | redox_syscall = "0.5" 12 | redox-daemon = "0.1" 13 | 14 | common = { path = "../../common" } 15 | driver-network = { path = "../driver-network" } 16 | pcid = { path = "../../pcid" } 17 | -------------------------------------------------------------------------------- /net/rtl8168d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rtl8168d" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | bitflags = "2" 8 | libredox = "0.1.3" 9 | log = "0.4" 10 | redox_event = "0.4.1" 11 | redox_syscall = "0.5" 12 | redox-daemon = "0.1" 13 | 14 | common = { path = "../../common" } 15 | driver-network = { path = "../driver-network" } 16 | pcid = { path = "../../pcid" } 17 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: "redoxos/redoxer:latest" 2 | 3 | stages: 4 | - build 5 | 6 | # TODO? 7 | # - test 8 | 9 | # TODO check if all drivers build 10 | 11 | fmt: 12 | stage: build 13 | needs: [] 14 | script: 15 | - rustup component add rustfmt-preview 16 | # TODO add more packages as they get formatted 17 | - CHECK_ONLY=1 ./fmt.sh 18 | 19 | # TODO: unit tests 20 | -------------------------------------------------------------------------------- /common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "common" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 6 | license = "MIT" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | libredox = "0.1.3" 12 | log = "0.4" 13 | redox_syscall = { version = "0.5.10", features = ["std"] } 14 | redox-log = "0.1.2" 15 | -------------------------------------------------------------------------------- /hwd/src/backend/legacy.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | use super::Backend; 4 | 5 | pub struct LegacyBackend; 6 | 7 | impl Backend for LegacyBackend { 8 | fn new() -> Result> { 9 | Ok(Self) 10 | } 11 | 12 | fn probe(&mut self) -> Result<(), Box> { 13 | log::info!("TODO: handle driver spawning from legacy backend"); 14 | Ok(()) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /inputd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "inputd" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Anhad Singh "] 6 | 7 | [dependencies] 8 | anyhow = "1.0.71" 9 | log = "0.4.19" 10 | redox-daemon = "0.1.2" 11 | redox_syscall = { version = "0.5", features = ["std"] } 12 | orbclient = "0.3.27" 13 | libredox = "0.1.3" 14 | 15 | common = { path = "../common" } 16 | redox-scheme = "0.6.2" 17 | -------------------------------------------------------------------------------- /pcid-spawner/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pcid-spawner" 3 | version = "0.1.0" 4 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 5 | edition = "2021" 6 | license = "MIT" 7 | 8 | [dependencies] 9 | anyhow = "1" 10 | log = "0.4" 11 | pico-args = "0.5" 12 | redox_syscall = "0.5.9" 13 | serde = { version = "1", features = ["derive"] } 14 | toml = "0.5" 15 | 16 | common = { path = "../common" } 17 | pcid = { path = "../pcid" } 18 | -------------------------------------------------------------------------------- /net/ixgbed/config.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "Intel 10G NIC" 3 | class = 0x02 4 | ids = { 0x8086 = [0x10F7, 0x1514, 0x1517, 0x151C, 0x10F9, 0x10FB, 0x152a, 0x1529, 0x1507, 0x154D, 0x1557, 0x10FC, 0x10F8, 0x154F, 0x1528, 0x154A, 0x1558, 0x1560, 0x1563, 0x15D1, 0x15AA, 0x15AB, 0x15AC, 0x15AD, 0x15AE, 0x15B0, 0x15C2, 0x15C3, 0x15C4, 0x15C6, 0x15C7, 0x15C8, 0x15CE, 0x15E4, 0x15E5, 0x10ED, 0x1515, 0x1565, 0x15A8, 0x15C5] } 5 | command = ["ixgbed"] 6 | -------------------------------------------------------------------------------- /storage/ahcid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ahcid" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bitflags = "1.2" 8 | byteorder = "1.2" 9 | log = "0.4" 10 | redox-daemon = "0.1" 11 | redox_syscall = { version = "0.5", features = ["std"] } 12 | 13 | common = { path = "../../common" } 14 | driver-block = { path = "../driver-block" } 15 | pcid = { path = "../../pcid" } 16 | libredox = "0.1.3" 17 | redox_event = "0.4" 18 | -------------------------------------------------------------------------------- /audio/ihdad/src/hda/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | pub mod cmdbuff; 3 | pub mod common; 4 | pub mod device; 5 | pub mod node; 6 | pub mod stream; 7 | 8 | pub use self::node::*; 9 | pub use self::stream::*; 10 | 11 | pub use self::cmdbuff::*; 12 | pub use self::device::IntelHDA; 13 | pub use self::stream::BitsPerSample; 14 | pub use self::stream::BufferDescriptorListEntry; 15 | pub use self::stream::StreamBuffer; 16 | pub use self::stream::StreamDescriptorRegs; 17 | -------------------------------------------------------------------------------- /virtio-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod spec; 2 | pub mod transport; 3 | pub mod utils; 4 | 5 | mod probe; 6 | 7 | #[cfg(target_arch = "aarch64")] 8 | #[path = "arch/aarch64.rs"] 9 | mod arch; 10 | 11 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 12 | #[path = "arch/x86.rs"] 13 | mod arch; 14 | 15 | #[cfg(target_arch = "riscv64")] 16 | #[path = "arch/riscv64.rs"] 17 | mod arch; 18 | 19 | pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; 20 | -------------------------------------------------------------------------------- /usb/xhcid/src/usb/interface.rs: -------------------------------------------------------------------------------- 1 | use plain::Plain; 2 | 3 | /// 4 | #[repr(C, packed)] 5 | #[derive(Clone, Copy, Debug, Default)] 6 | pub struct InterfaceDescriptor { 7 | pub length: u8, 8 | pub kind: u8, 9 | pub number: u8, 10 | pub alternate_setting: u8, 11 | pub endpoints: u8, 12 | pub class: u8, 13 | pub sub_class: u8, 14 | pub protocol: u8, 15 | pub interface_str: u8, 16 | } 17 | 18 | unsafe impl Plain for InterfaceDescriptor {} 19 | -------------------------------------------------------------------------------- /amlserde/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "amlserde" 3 | version = "0.0.1" 4 | authors = ["Ron Williams"] 5 | repository = "https://gitlab.redox-os.org/redox-os/drivers" 6 | description = "Library for serializing AML symbols" 7 | categories = ["hardware-support"] 8 | license = "MIT/Apache-2.0" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | acpi = { git = "https://github.com/jackpot51/acpi.git" } 13 | serde = { version = "1.0", features = ["derive"] } 14 | toml = "0.7.3" 15 | -------------------------------------------------------------------------------- /graphics/fbbootlogd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fbbootlogd" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | orbclient = "0.3.27" 8 | ransid = "0.4" 9 | redox_event = "0.4" 10 | redox_syscall = "0.5" 11 | redox-daemon = "0.1" 12 | redox-scheme = "0.6.2" 13 | 14 | console-draw = { path = "../console-draw" } 15 | graphics-ipc = { path = "../graphics-ipc" } 16 | inputd = { path = "../../inputd" } 17 | libredox = "0.1.3" 18 | 19 | [features] 20 | default = [] 21 | -------------------------------------------------------------------------------- /graphics/vesad/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vesad" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | orbclient = "0.3.27" 8 | ransid = "0.4" 9 | redox_syscall = "0.5" 10 | redox-daemon = "0.1" 11 | redox_event = "0.4.1" 12 | 13 | common = { path = "../../common" } 14 | driver-graphics = { path = "../driver-graphics" } 15 | graphics-ipc = { path = "../graphics-ipc" } 16 | inputd = { path = "../../inputd" } 17 | libredox = "0.1.3" 18 | 19 | [features] 20 | default = [] 21 | -------------------------------------------------------------------------------- /storage/lived/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lived" 3 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 4 | version = "0.1.0" 5 | edition = "2021" 6 | license = "MIT" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | anyhow = "1" 12 | libredox = "0.1.3" 13 | redox-daemon = "0.1" 14 | redox_syscall = { version = "0.5", features = ["std"] } 15 | redox_event = "0.4" 16 | driver-block = { path = "../driver-block" } 17 | -------------------------------------------------------------------------------- /usb/xhcid/drivers.toml: -------------------------------------------------------------------------------- 1 | [[drivers]] 2 | name = "SCSI over USB" 3 | class = 8 # Mass Storage class 4 | subclass = 6 # SCSI transparent command set 5 | command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] 6 | 7 | [[drivers]] 8 | name = "USB HUB" 9 | class = 9 # HUB class 10 | subclass = -1 11 | command = ["usbhubd", "$SCHEME", "$PORT", "$IF_NUM"] 12 | 13 | [[drivers]] 14 | name = "USB HID" 15 | class = 3 # HID class 16 | subclass = -1 17 | command = ["usbhidd", "$SCHEME", "$PORT", "$IF_NUM"] 18 | -------------------------------------------------------------------------------- /net/virtio-netd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "virtio-netd" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | log = "0.4" 8 | static_assertions = "1.1.0" 9 | futures = { version = "0.3.28", features = ["executor"] } 10 | 11 | virtio-core = { path = "../../virtio-core" } 12 | pcid = { path = "../../pcid" } 13 | common = { path = "../../common" } 14 | driver-network = { path = "../driver-network" } 15 | 16 | redox-daemon = "0.1" 17 | redox_syscall = "0.5" 18 | libredox = "0.1.3" 19 | -------------------------------------------------------------------------------- /storage/driver-block/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver-block" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | executor = { path = "../../executor" } 8 | partitionlib = { path = "../partitionlib" } 9 | 10 | libredox = "0.1.3" 11 | log = "0.4" 12 | 13 | # TODO: migrate virtio to our executor 14 | futures = { version = "0.3.28", features = ["executor"] } 15 | 16 | redox-daemon = "0.1" 17 | redox_syscall = { version = "0.5", features = ["std"] } 18 | redox-scheme = "0.6.2" 19 | -------------------------------------------------------------------------------- /storage/bcm2835-sdhcid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bcm2835-sdhcid" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | fdt = { git = "https://github.com/repnop/fdt.git" } 10 | common = { path = "../../common" } 11 | driver-block = { path = "../driver-block" } 12 | 13 | redox-daemon = "0.1" 14 | libredox = "0.1.3" 15 | redox_syscall = { version = "0.5", features = ["std"] } 16 | redox_event = "0.4" 17 | -------------------------------------------------------------------------------- /virtio-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "virtio-core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Anhad Singh "] 6 | 7 | [dependencies] 8 | static_assertions = "1.1.0" 9 | bitflags = "2.3.2" 10 | redox_syscall = "0.5" 11 | libredox = "0.1.3" 12 | log = "0.4" 13 | thiserror = "1.0.40" 14 | futures = { version = "0.3.28", features = ["executor"] } 15 | crossbeam-queue = "0.3.8" 16 | 17 | redox_event = "0.4.1" 18 | 19 | common = { path = "../common" } 20 | pcid = { path = "../pcid" } 21 | -------------------------------------------------------------------------------- /graphics/fbcond/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fbcond" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | log = "0.4" 8 | orbclient = "0.3.27" 9 | ransid = "0.4" 10 | redox_event = "0.4" 11 | redox_syscall = "0.5" 12 | redox-daemon = "0.1" 13 | redox-scheme = "0.4" 14 | 15 | common = { path = "../../common" } 16 | console-draw = { path = "../console-draw" } 17 | graphics-ipc = { path = "../graphics-ipc" } 18 | inputd = { path = "../../inputd" } 19 | libredox = "0.1.3" 20 | 21 | [features] 22 | default = [] 23 | -------------------------------------------------------------------------------- /usb/xhcid/src/xhci/runtime.rs: -------------------------------------------------------------------------------- 1 | use common::io::Mmio; 2 | 3 | #[repr(C, packed)] 4 | pub struct Interrupter { 5 | pub iman: Mmio, 6 | pub imod: Mmio, 7 | pub erstsz: Mmio, 8 | _rsvd: Mmio, 9 | pub erstba_low: Mmio, 10 | pub erstba_high: Mmio, 11 | pub erdp_low: Mmio, 12 | pub erdp_high: Mmio, 13 | } 14 | 15 | #[repr(C, packed)] 16 | pub struct RuntimeRegs { 17 | pub mfindex: Mmio, 18 | _rsvd: [Mmio; 7], 19 | pub ints: [Interrupter; 1024], 20 | } 21 | -------------------------------------------------------------------------------- /input/usbhidd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "usbhidd" 3 | version = "0.1.0" 4 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 5 | edition = "2018" 6 | license = "MIT" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | bitflags = "2" 12 | log = "0.4" 13 | orbclient = "0.3.47" 14 | redox_syscall = "0.5" 15 | rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } 16 | xhcid = { path = "../../usb/xhcid" } 17 | 18 | common = { path = "../../common" } 19 | inputd = { path = "../../inputd" } 20 | -------------------------------------------------------------------------------- /storage/usbscsid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "usbscsid" 3 | version = "0.1.0" 4 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 5 | edition = "2021" 6 | license = "MIT" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | base64 = "0.11" # Only for debugging 12 | libredox = "0.1.3" 13 | plain = "0.2" 14 | driver-block = { path = "../driver-block" } 15 | redox-daemon = "0.1" 16 | redox_event = "0.4" 17 | redox_syscall = { version = "0.5", features = ["std"] } 18 | thiserror = "1" 19 | xhcid = { path = "../../usb/xhcid" } 20 | -------------------------------------------------------------------------------- /pcid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pcid" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [[bin]] 7 | name = "pcid" 8 | path = "src/main.rs" 9 | 10 | [lib] 11 | name = "pcid_interface" 12 | path = "src/lib.rs" 13 | 14 | [dependencies] 15 | bincode = "1.2" 16 | fdt = "0.1.5" 17 | libc = "0.2" 18 | log = "0.4" 19 | pci_types = "0.10" 20 | pico-args = { version = "0.5", features = ["combined-flags"] } 21 | plain = "0.2" 22 | redox-daemon = "0.1" 23 | redox-scheme = "0.6.2" 24 | redox_syscall = "0.5.9" 25 | serde = { version = "1", features = ["derive"] } 26 | 27 | common = { path = "../common" } 28 | libredox = "0.1.3" 29 | -------------------------------------------------------------------------------- /storage/nvmed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nvmed" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | arrayvec = "0.7" 8 | bitflags = "2" 9 | futures = "0.3" 10 | libredox = "0.1.3" 11 | log = "0.4" 12 | parking_lot = "0.12.1" 13 | redox-daemon = "0.1" 14 | redox_event = "0.4.1" 15 | redox_syscall = { version = "0.5", features = ["std"] } 16 | smallvec = "1" 17 | 18 | executor = { path = "../../executor" } 19 | common = { path = "../../common" } 20 | driver-block = { path = "../driver-block" } 21 | partitionlib = { path = "../partitionlib" } 22 | pcid = { path = "../../pcid" } 23 | 24 | [features] 25 | default = [] 26 | -------------------------------------------------------------------------------- /storage/virtio-blkd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "virtio-blkd" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Anhad Singh "] 6 | 7 | [dependencies] 8 | anyhow = "1.0.71" 9 | log = "0.4" 10 | thiserror = "1.0.40" 11 | static_assertions = "1.1.0" 12 | futures = { version = "0.3.28", features = ["executor"] } 13 | spin = "*" 14 | 15 | redox-daemon = "0.1" 16 | redox_event = "0.4" 17 | redox_syscall = { version = "0.5", features = ["std"] } 18 | 19 | common = { path = "../../common" } 20 | driver-block = { path = "../driver-block" } 21 | pcid = { path = "../../pcid" } 22 | virtio-core = { path = "../../virtio-core" } 23 | libredox = "0.1.3" 24 | -------------------------------------------------------------------------------- /graphics/virtio-gpud/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "virtio-gpud" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Anhad Singh "] 6 | 7 | [dependencies] 8 | log = "0.4" 9 | static_assertions = "1.1.0" 10 | futures = { version = "0.3.28", features = ["executor"] } 11 | anyhow = "1.0.71" 12 | 13 | common = { path = "../../common" } 14 | driver-graphics = { path = "../driver-graphics" } 15 | graphics-ipc = { path = "../graphics-ipc" } 16 | virtio-core = { path = "../../virtio-core" } 17 | pcid = { path = "../../pcid" } 18 | inputd = { path = "../../inputd" } 19 | 20 | redox-daemon = "0.1" 21 | redox_event = "0.4.1" 22 | redox_syscall = "0.5" 23 | orbclient = "0.3.27" 24 | spin = "0.9.8" 25 | libredox = "0.1.3" 26 | -------------------------------------------------------------------------------- /usb/xhcid/src/usb/config.rs: -------------------------------------------------------------------------------- 1 | #[repr(C, packed)] 2 | #[derive(Clone, Copy, Debug, Default)] 3 | pub struct ConfigDescriptor { 4 | pub length: u8, 5 | pub kind: u8, 6 | pub total_length: u16, 7 | pub interfaces: u8, 8 | pub configuration_value: u8, 9 | pub configuration_str: u8, 10 | pub attributes: u8, 11 | pub max_power: u8, 12 | } 13 | 14 | unsafe impl plain::Plain for ConfigDescriptor {} 15 | 16 | #[repr(C, packed)] 17 | #[derive(Clone, Copy, Debug, Default)] 18 | pub struct OtherSpeedConfig { 19 | pub length: u8, 20 | pub kind: u8, 21 | pub total_length: u16, 22 | pub interfaces: u8, 23 | pub configuration_value: u8, 24 | pub configuration_str: u8, 25 | pub attributes: u8, 26 | pub max_power: u8, 27 | } 28 | -------------------------------------------------------------------------------- /acpid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "acpid" 3 | version = "0.1.0" 4 | authors = ["4lDO2 <4lDO2@protonmail.com>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | acpi = { git = "https://github.com/jackpot51/acpi.git" } 11 | log = "0.4" 12 | num-derive = "0.3" 13 | num-traits = "0.2" 14 | parking_lot = "0.12" 15 | plain = "0.2.3" 16 | redox-daemon = "0.1" 17 | redox_syscall = "0.5.6" 18 | redox_event = "0.4.1" 19 | rustc-hash = "1.1.0" 20 | thiserror = "1" 21 | ron = "0.8.1" 22 | 23 | amlserde = { path = "../amlserde" } 24 | common = { path = "../common" } 25 | libredox = "0.1.3" 26 | redox-scheme = "0.6.2" 27 | arrayvec = "0.7.6" 28 | serde = { version = "1.0.228", features = ["derive"] } 29 | -------------------------------------------------------------------------------- /initfs.toml: -------------------------------------------------------------------------------- 1 | ## Drivers for InitFS ## 2 | 3 | # ahcid 4 | [[drivers]] 5 | name = "AHCI storage" 6 | class = 1 7 | subclass = 6 8 | command = ["/scheme/initfs/lib/drivers/ahcid"] 9 | 10 | # ided 11 | [[drivers]] 12 | name = "IDE storage" 13 | class = 1 14 | subclass = 1 15 | command = ["/scheme/initfs/lib/drivers/ided"] 16 | 17 | # nvmed 18 | [[drivers]] 19 | name = "NVME storage" 20 | class = 1 21 | subclass = 8 22 | command = ["/scheme/initfs/lib/drivers/nvmed"] 23 | 24 | [[drivers]] 25 | name = "virtio-blk" 26 | class = 1 27 | subclass = 0 28 | vendor = 0x1AF4 29 | device = 0x1001 30 | command = ["/scheme/initfs/lib/drivers/virtio-blkd"] 31 | 32 | [[drivers]] 33 | name = "virtio-gpu" 34 | class = 3 35 | vendor = 0x1AF4 36 | device = 0x1050 37 | command = ["/scheme/initfs/lib/drivers/virtio-gpud"] 38 | -------------------------------------------------------------------------------- /usb/xhcid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xhcid" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [[bin]] 7 | name = "xhcid" 8 | path = "src/main.rs" 9 | 10 | [lib] 11 | name = "xhcid_interface" 12 | path = "src/lib.rs" 13 | 14 | [dependencies] 15 | bitflags = "1" 16 | chashmap = "2.2.2" 17 | crossbeam-channel = "0.4" 18 | futures = "0.3" 19 | plain = "0.2" 20 | lazy_static = "1.4" 21 | log = "0.4" 22 | redox-daemon = "0.1" 23 | redox_event = "0.4.1" 24 | redox-scheme = "0.6.2" 25 | redox_syscall = "0.5" 26 | serde = { version = "1", features = ["derive"] } 27 | serde_json = "1" 28 | smallvec = { version = "1", features = ["serde"] } 29 | thiserror = "1" 30 | toml = "0.5" 31 | 32 | common = { path = "../../common" } 33 | pcid = { path = "../../pcid" } 34 | libredox = "0.1.3" 35 | regex = "1.10.6" 36 | -------------------------------------------------------------------------------- /.gitlab/merge_request_templates/Merge_request_template.md: -------------------------------------------------------------------------------- 1 | **Problem**: [describe the problem you try to solve with this PR.] 2 | 3 | **Solution**: [describe carefully what you change by this PR.] 4 | 5 | **Changes introduced by this pull request**: 6 | 7 | - [...] 8 | - [...] 9 | - [...] 10 | 11 | **Drawbacks**: [if any, describe the drawbacks of this pull request.] 12 | 13 | **TODOs**: [what is not done yet.] 14 | 15 | **Fixes**: [what issues this fixes.] 16 | 17 | **State**: [the state of this PR, e.g. WIP, ready, etc.] 18 | 19 | **Blocking/related**: [issues or PRs blocking or being related to this issue.] 20 | 21 | **Other**: [optional: for other relevant information that should be known or cannot be described in the other fields.] 22 | 23 | ------ 24 | 25 | _The above template is not necessary for smaller PRs._ 26 | -------------------------------------------------------------------------------- /rtcd/src/main.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | 3 | // TODO: Do not use target architecture to distinguish these. 4 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 5 | mod x86; 6 | 7 | /// The rtc driver runs only once, being perhaps the first of all processes that init starts (since 8 | /// early logging benefits from knowing the time, even though this can be adjusted later once the 9 | /// time is known). The sole job of `rtcd` is to read from the hardware real-time clock, and then 10 | /// write the offset to the kernel. 11 | 12 | fn main() -> Result<()> { 13 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 14 | { 15 | common::acquire_port_io_rights().context("failed to set iopl")?; 16 | 17 | let time_s = self::x86::get_time(); 18 | let time_ns = u128::from(time_s) * 1_000_000_000; 19 | 20 | std::fs::write("/scheme/sys/update_time_offset", &time_ns.to_ne_bytes()) 21 | .context("failed to write to time offset")?; 22 | } 23 | // TODO: aarch64 is currently handled in the kernel 24 | 25 | Ok(()) 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Redox OS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vboxd/src/bga.rs: -------------------------------------------------------------------------------- 1 | use common::io::{Io, Pio}; 2 | 3 | const BGA_INDEX_XRES: u16 = 1; 4 | const BGA_INDEX_YRES: u16 = 2; 5 | const BGA_INDEX_BPP: u16 = 3; 6 | const BGA_INDEX_ENABLE: u16 = 4; 7 | 8 | pub struct Bga { 9 | index: Pio, 10 | data: Pio, 11 | } 12 | 13 | impl Bga { 14 | pub fn new() -> Bga { 15 | Bga { 16 | index: Pio::new(0x1CE), 17 | data: Pio::new(0x1CF), 18 | } 19 | } 20 | 21 | fn read(&mut self, index: u16) -> u16 { 22 | self.index.write(index); 23 | self.data.read() 24 | } 25 | 26 | fn write(&mut self, index: u16, data: u16) { 27 | self.index.write(index); 28 | self.data.write(data); 29 | } 30 | 31 | pub fn width(&mut self) -> u16 { 32 | self.read(BGA_INDEX_XRES) 33 | } 34 | 35 | pub fn height(&mut self) -> u16 { 36 | self.read(BGA_INDEX_YRES) 37 | } 38 | 39 | pub fn set_size(&mut self, width: u16, height: u16) { 40 | self.write(BGA_INDEX_ENABLE, 0); 41 | self.write(BGA_INDEX_XRES, width); 42 | self.write(BGA_INDEX_YRES, height); 43 | self.write(BGA_INDEX_BPP, 32); 44 | self.write(BGA_INDEX_ENABLE, 0x41); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/src/timeout.rs: -------------------------------------------------------------------------------- 1 | use std::{thread, time::{Duration, Instant}}; 2 | 3 | pub struct Timeout { 4 | instant: Instant, 5 | duration: Duration, 6 | } 7 | 8 | impl Timeout { 9 | #[inline] 10 | pub fn new(duration: Duration) -> Self { 11 | Self { 12 | instant: Instant::now(), 13 | duration, 14 | } 15 | } 16 | 17 | #[inline] 18 | pub fn from_micros(micros: u64) -> Self { 19 | Self::new(Duration::from_micros(micros)) 20 | } 21 | 22 | #[inline] 23 | pub fn from_millis(millis: u64) -> Self { 24 | Self::new(Duration::from_millis(millis)) 25 | } 26 | 27 | #[inline] 28 | pub fn from_secs(secs: u64) -> Self { 29 | Self::new(Duration::from_secs(secs)) 30 | } 31 | 32 | #[inline] 33 | pub fn run(&self) -> Result<(), ()> { 34 | if self.instant.elapsed() < self.duration { 35 | // Sleeps in Redox are only evaluated on PIT ticks (a few ms), which is not 36 | // short enough for a reasonably responsive timeout. However, the clock is 37 | // highly accurate. So, we yield instead of sleep to reduce latency. 38 | //TODO: allow timeout that spins instead of yields? 39 | std::thread::yield_now(); 40 | Ok(()) 41 | } else { 42 | Err(()) 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /storage/partitionlib/tests/test.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | use partitionlib::{ 4 | get_partitions, LogicalBlockSize, Partition, PartitionTable, PartitionTableKind, 5 | }; 6 | 7 | fn get_partitions_from_file(path: &str) -> PartitionTable { 8 | let mut file = File::open(path).unwrap(); 9 | get_partitions(&mut file, LogicalBlockSize::Lb512) 10 | .unwrap() 11 | .unwrap() 12 | } 13 | 14 | // NOTE: The following tests rely on outside resource files being correct. 15 | #[test] 16 | fn gpt() { 17 | let table = get_partitions_from_file("./resources/disk.img"); 18 | assert_eq!(table.kind, PartitionTableKind::Gpt); 19 | assert_eq!( 20 | &table.partitions, 21 | &[Partition { 22 | flags: Some(0), 23 | name: Some("bug".to_owned()), 24 | uuid: Some(uuid::Uuid::parse_str("b665fba9-74d5-4069-a6b9-5ba3a164fdfe").unwrap()), // Microsoft basic data 25 | size: 957, 26 | start_lba: 34, 27 | }] 28 | ); 29 | } 30 | 31 | #[test] 32 | fn mbr() { 33 | let table = get_partitions_from_file("./resources/disk_mbr.img"); 34 | assert_eq!(table.kind, PartitionTableKind::Mbr); 35 | assert_eq!( 36 | &table.partitions, 37 | &[Partition { 38 | flags: None, 39 | name: None, 40 | uuid: None, 41 | size: 3, 42 | start_lba: 1, 43 | }] 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /net/ixgbed/README.md: -------------------------------------------------------------------------------- 1 | # ixgbed (a.k.a. ixy.rs on Redox) 2 | 3 | ixgbed is the Redox port of [ixy.rs](https://github.com/ixy-languages/ixy.rs), a Rust rewrite of the [ixy](https://github.com/emmericp/ixy) userspace network driver. 4 | It is designed to be readable, idiomatic Rust code. 5 | It supports Intel 82599 10GbE NICs (`ixgbe` family). 6 | 7 | ## Features 8 | 9 | * first 10 Gbit/s network driver on Redox 10 | * transmitting 250 times faster than e1000 / rtl8168 driver 11 | * MSI-X interrupts (not supported by Redox yet) 12 | * less than 1000 lines of code for the driver 13 | * documented code 14 | 15 | ## Build instructions 16 | 17 | See the [Redox README](https://gitlab.redox-os.org/redox-os/redox/blob/master/README.md) for build instructions. 18 | 19 | To run ixgbed on Redox (in case the driver is not shipped with Redox anymore) 20 | 21 | * clone this project into `cookbook/recipes/drivers/source/` 22 | * create an entry for ixgbed in `cookbook/recipes/drivers/source/Cargo.toml` 23 | * check if your ixgbe device is included in `config.toml` 24 | * touch `filesystem.toml` in Redox's root directory, build Redox and run it 25 | 26 | ## Usage 27 | 28 | To test the driver's transmit and forwarding capabilities, have a look at [rheinfall](https://github.com/ackxolotl/rheinfall), a simple packet generator / forwarder application. 29 | 30 | ## Docs 31 | 32 | ixgbed contains documentation that can be created and viewed by running 33 | 34 | ``` 35 | cargo doc --open 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "common", 4 | "executor", 5 | 6 | "acpid", 7 | "hwd", 8 | "pcid", 9 | "pcid-spawner", 10 | "rtcd", 11 | "vboxd", 12 | "inputd", 13 | "virtio-core", 14 | 15 | "audio/ac97d", 16 | "audio/ihdad", 17 | "audio/sb16d", 18 | 19 | "graphics/bgad", 20 | "graphics/console-draw", 21 | "graphics/fbbootlogd", 22 | "graphics/driver-graphics", 23 | "graphics/fbcond", 24 | "graphics/graphics-ipc", 25 | "graphics/vesad", 26 | "graphics/virtio-gpud", 27 | 28 | "input/ps2d", 29 | "input/usbhidd", 30 | 31 | "net/alxd", 32 | "net/driver-network", 33 | "net/e1000d", 34 | "net/ixgbed", 35 | "net/rtl8139d", 36 | "net/rtl8168d", 37 | "net/virtio-netd", 38 | 39 | "storage/ahcid", 40 | "storage/bcm2835-sdhcid", 41 | "storage/driver-block", 42 | "storage/ided", 43 | "storage/lived", # TODO: not really a driver... 44 | "storage/nvmed", 45 | "storage/usbscsid", 46 | "storage/virtio-blkd", 47 | 48 | "usb/xhcid", 49 | "usb/usbctl", 50 | "usb/usbhubd", 51 | ] 52 | 53 | [profile.release] 54 | lto = "fat" 55 | 56 | [patch.crates-io] 57 | mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } 58 | orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } 59 | redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } 60 | -------------------------------------------------------------------------------- /hwd/src/backend/devicetree.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fs}; 2 | 3 | use super::Backend; 4 | 5 | pub struct DeviceTreeBackend { 6 | dtb: Vec, 7 | } 8 | 9 | impl DeviceTreeBackend { 10 | fn dump(node: &fdt::node::FdtNode<'_, '_>, level: usize) { 11 | let mut line = String::new(); 12 | for _ in 0..level { 13 | line.push_str(" "); 14 | } 15 | line.push_str(node.name); 16 | if let Some(compatible) = node.compatible() { 17 | line.push_str(":"); 18 | for id in compatible.all() { 19 | line.push_str(" "); 20 | line.push_str(id); 21 | } 22 | } 23 | log::debug!("{}", line); 24 | for child in node.children() { 25 | Self::dump(&child, level + 1); 26 | } 27 | } 28 | } 29 | 30 | impl Backend for DeviceTreeBackend { 31 | fn new() -> Result> { 32 | let dtb = fs::read("/scheme/kernel.dtb")?; 33 | let dt = fdt::Fdt::new(&dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; 34 | Ok(Self { dtb }) 35 | } 36 | 37 | fn probe(&mut self) -> Result<(), Box> { 38 | let dt = fdt::Fdt::new(&self.dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; 39 | let root = dt 40 | .find_node("/") 41 | .ok_or_else(|| format!("failed to find root node"))?; 42 | Self::dump(&root, 0); 43 | Ok(()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pcid/src/driver_interface/cap.rs: -------------------------------------------------------------------------------- 1 | use pci_types::capability::PciCapabilityAddress; 2 | use pci_types::ConfigRegionAccess; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] 6 | pub struct VendorSpecificCapability { 7 | pub data: Vec, 8 | } 9 | 10 | impl VendorSpecificCapability { 11 | pub unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { 12 | let dword = access.read(addr.address, addr.offset); 13 | let length = ((dword >> 16) & 0xFF) as u16; 14 | // let next = (dword >> 8) & 0xFF; 15 | // log::trace!( 16 | // "Vendor specific offset: {:#02x} next: {next:#02x} cap len: {length:#02x}", 17 | // addr.offset 18 | // ); 19 | let data = if length > 0 { 20 | assert!( 21 | length > 3 && length % 4 == 0, 22 | "invalid range length: {}", 23 | length 24 | ); 25 | let mut raw_data = { 26 | (addr.offset..addr.offset + length) 27 | .step_by(4) 28 | .flat_map(|offset| access.read(addr.address, offset).to_le_bytes()) 29 | .collect::>() 30 | }; 31 | raw_data.drain(3..).collect() 32 | } else { 33 | log::warn!("Vendor specific capability is invalid"); 34 | Vec::new() 35 | }; 36 | VendorSpecificCapability { data } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /usb/xhcid/src/xhci/event.rs: -------------------------------------------------------------------------------- 1 | use common::io::{Io, Mmio}; 2 | use syscall::error::Result; 3 | 4 | use common::dma::Dma; 5 | 6 | use super::ring::Ring; 7 | use super::trb::Trb; 8 | use super::Xhci; 9 | 10 | #[repr(C, packed)] 11 | pub struct EventRingSte { 12 | pub address_low: Mmio, 13 | pub address_high: Mmio, 14 | pub size: Mmio, 15 | _rsvd: Mmio, 16 | _rsvd2: Mmio, 17 | } 18 | 19 | // TODO: Use atomic operations, and perhaps an occasional lock for reallocating. 20 | pub struct EventRing { 21 | pub ste: Dma<[EventRingSte]>, 22 | pub ring: Ring, 23 | } 24 | 25 | impl EventRing { 26 | pub fn new(ac64: bool) -> Result { 27 | let mut ring = EventRing { 28 | ste: unsafe { Xhci::::alloc_dma_zeroed_unsized_raw(ac64, 1)? }, 29 | ring: Ring::new::(ac64, 256, false)?, 30 | }; 31 | 32 | ring.ste[0] 33 | .address_low 34 | .write(ring.ring.trbs.physical() as u32); 35 | ring.ste[0] 36 | .address_high 37 | .write((ring.ring.trbs.physical() as u64 >> 32) as u32); 38 | ring.ste[0].size.write(ring.ring.trbs.len() as u16); 39 | 40 | Ok(ring) 41 | } 42 | 43 | pub fn next(&mut self) -> &mut Trb { 44 | self.ring.next().0 45 | } 46 | pub fn erdp(&self) -> u64 { 47 | self.ring.register() & 0xFFFF_FFFF_FFFF_FFF0 48 | } 49 | pub fn erstba(&self) -> u64 { 50 | self.ste.physical() as u64 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /virtio-core/src/arch/x86.rs: -------------------------------------------------------------------------------- 1 | use crate::transport::Error; 2 | 3 | use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id}; 4 | use std::fs::File; 5 | 6 | use crate::MSIX_PRIMARY_VECTOR; 7 | 8 | use pcid_interface::*; 9 | 10 | pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { 11 | // Extended message signaled interrupts. 12 | let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { 13 | PciFeatureInfo::MsiX(capability) => capability, 14 | _ => unreachable!(), 15 | }; 16 | let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; 17 | 18 | // Allocate the primary MSI vector. 19 | // FIXME allow the driver to register multiple MSI-X vectors 20 | // FIXME move this MSI-X registering code into pcid_interface or pcid itself 21 | let interrupt_handle = { 22 | let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); 23 | 24 | let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); 25 | let (msg_addr_and_data, interrupt_handle) = 26 | allocate_single_interrupt_vector_for_msi(destination_id); 27 | table_entry_pointer.write_addr_and_data(msg_addr_and_data); 28 | table_entry_pointer.unmask(); 29 | 30 | interrupt_handle 31 | }; 32 | 33 | pcid_handle.enable_feature(PciFeature::MsiX); 34 | 35 | log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); 36 | Ok(interrupt_handle) 37 | } 38 | -------------------------------------------------------------------------------- /graphics/bgad/src/bga.rs: -------------------------------------------------------------------------------- 1 | const BGA_INDEX_XRES: u16 = 1; 2 | const BGA_INDEX_YRES: u16 = 2; 3 | const BGA_INDEX_BPP: u16 = 3; 4 | const BGA_INDEX_ENABLE: u16 = 4; 5 | 6 | pub struct Bga { 7 | bar: *mut u8, 8 | } 9 | 10 | impl Bga { 11 | pub unsafe fn new(bar: *mut u8) -> Bga { 12 | Bga { bar } 13 | } 14 | 15 | fn bochs_dispi_addr(&mut self, index: u16) -> *mut u16 { 16 | assert!(index <= 0x10); 17 | unsafe { 18 | self.bar 19 | .byte_add(0x500) 20 | .cast::() 21 | .add(usize::from(index)) 22 | } 23 | } 24 | 25 | fn bochs_dispi_read(&mut self, index: u16) -> u16 { 26 | unsafe { self.bochs_dispi_addr(index).read_volatile() } 27 | } 28 | 29 | fn bochs_dispi_write(&mut self, index: u16, data: u16) { 30 | assert!(index <= 0x10); 31 | unsafe { 32 | self.bochs_dispi_addr(index).write_volatile(data); 33 | } 34 | } 35 | 36 | pub fn width(&mut self) -> u16 { 37 | self.bochs_dispi_read(BGA_INDEX_XRES) 38 | } 39 | 40 | pub fn height(&mut self) -> u16 { 41 | self.bochs_dispi_read(BGA_INDEX_YRES) 42 | } 43 | 44 | pub fn set_size(&mut self, width: u16, height: u16) { 45 | self.bochs_dispi_write(BGA_INDEX_ENABLE, 0); 46 | self.bochs_dispi_write(BGA_INDEX_XRES, width); 47 | self.bochs_dispi_write(BGA_INDEX_YRES, height); 48 | self.bochs_dispi_write(BGA_INDEX_BPP, 32); 49 | self.bochs_dispi_write(BGA_INDEX_ENABLE, 0x41); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /storage/partitionlib/src/mbr.rs: -------------------------------------------------------------------------------- 1 | use scroll::{Pread, Pwrite}; 2 | use std::io::{self, Read, Seek}; 3 | 4 | #[derive(Clone, Copy, Debug, Pread, Pwrite)] 5 | pub(crate) struct Entry { 6 | pub(crate) drive_attrs: u8, 7 | pub(crate) start_head: u8, 8 | pub(crate) start_cs: u16, 9 | pub(crate) sys_id: u8, 10 | pub(crate) end_head: u8, 11 | pub(crate) end_cs: u16, 12 | pub(crate) rel_sector: u32, 13 | pub(crate) len: u32, 14 | } 15 | 16 | #[derive(Pread, Pwrite)] 17 | pub(crate) struct Header { 18 | pub(crate) bootstrap: [u8; 446], 19 | pub(crate) first_entry: Entry, 20 | pub(crate) second_entry: Entry, 21 | pub(crate) third_entry: Entry, 22 | pub(crate) fourth_entry: Entry, 23 | pub(crate) last_signature: u16, // 0xAA55 24 | } 25 | 26 | pub(crate) fn read_header(device: &mut D) -> io::Result> { 27 | device.seek(io::SeekFrom::Start(0))?; 28 | 29 | let mut bytes = [0u8; 512]; 30 | device.read_exact(&mut bytes)?; 31 | 32 | let header: Header = bytes.pread_with(0, scroll::LE).unwrap(); 33 | 34 | if header.last_signature != 0xAA55 { 35 | return Ok(None); 36 | } 37 | 38 | Ok(Some(header)) 39 | } 40 | 41 | impl Header { 42 | pub(crate) fn partitions(&self) -> impl Iterator { 43 | [ 44 | self.first_entry, 45 | self.second_entry, 46 | self.third_entry, 47 | self.fourth_entry, 48 | ] 49 | .into_iter() 50 | .filter(Entry::is_valid) 51 | } 52 | } 53 | impl Entry { 54 | fn is_valid(&self) -> bool { 55 | (self.drive_attrs == 0 || self.drive_attrs == 0x80) && self.len != 0 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /pcid/src/driver_interface/id.rs: -------------------------------------------------------------------------------- 1 | use pci_types::device_type::DeviceType; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | /// All identifying information of a PCI function. 5 | #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] 6 | pub struct FullDeviceId { 7 | pub vendor_id: u16, 8 | pub device_id: u16, 9 | pub class: u8, 10 | pub subclass: u8, 11 | pub interface: u8, 12 | pub revision: u8, 13 | } 14 | 15 | impl FullDeviceId { 16 | pub fn display(&self) -> String { 17 | let mut string = format!( 18 | "{:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", 19 | self.vendor_id, 20 | self.device_id, 21 | self.class, 22 | self.subclass, 23 | self.interface, 24 | self.revision, 25 | self.class, 26 | ); 27 | let device_type = DeviceType::from((self.class, self.subclass)); 28 | match device_type { 29 | DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), 30 | DeviceType::IdeController => string.push_str(" IDE"), 31 | DeviceType::SataController => match self.interface { 32 | 0 => string.push_str(" SATA VND"), 33 | 1 => string.push_str(" SATA AHCI"), 34 | _ => (), 35 | }, 36 | DeviceType::UsbController => match self.interface { 37 | 0x00 => string.push_str(" UHCI"), 38 | 0x10 => string.push_str(" OHCI"), 39 | 0x20 => string.push_str(" EHCI"), 40 | 0x30 => string.push_str(" XHCI"), 41 | _ => (), 42 | }, 43 | DeviceType::NvmeController => string.push_str(" NVME"), 44 | _ => (), 45 | } 46 | string 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /graphics/graphics-ipc/src/common.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | 3 | // Keep synced with orbital's SyncRect 4 | // Technically orbital uses i32 rather than u32, but values larger than i32::MAX 5 | // would be a bug anyway. 6 | #[derive(Debug, Copy, Clone)] 7 | #[repr(C, packed)] 8 | pub struct Damage { 9 | pub x: u32, 10 | pub y: u32, 11 | pub width: u32, 12 | pub height: u32, 13 | } 14 | 15 | impl Damage { 16 | #[must_use] 17 | pub fn clip(mut self, width: u32, height: u32) -> Self { 18 | // Clip damage 19 | let x2 = self.x + self.width; 20 | self.x = cmp::min(self.x, width); 21 | if x2 > width { 22 | self.width = width - self.x; 23 | } 24 | 25 | let y2 = self.y + self.height; 26 | self.y = cmp::min(self.y, height); 27 | if y2 > height { 28 | self.height = height - self.y; 29 | } 30 | self 31 | } 32 | } 33 | 34 | pub struct DisplayMap { 35 | offscreen: *mut [u32], 36 | width: usize, 37 | height: usize, 38 | } 39 | 40 | impl DisplayMap { 41 | pub(crate) unsafe fn new(offscreen: *mut [u32], width: usize, height: usize) -> Self { 42 | DisplayMap { 43 | offscreen, 44 | width, 45 | height, 46 | } 47 | } 48 | 49 | pub fn ptr(&self) -> *const [u32] { 50 | self.offscreen 51 | } 52 | 53 | pub fn ptr_mut(&mut self) -> *mut [u32] { 54 | self.offscreen 55 | } 56 | 57 | pub fn width(&self) -> usize { 58 | self.width 59 | } 60 | 61 | pub fn height(&self) -> usize { 62 | self.height 63 | } 64 | } 65 | 66 | unsafe impl Send for DisplayMap {} 67 | unsafe impl Sync for DisplayMap {} 68 | 69 | impl Drop for DisplayMap { 70 | fn drop(&mut self) { 71 | unsafe { 72 | let _ = libredox::call::munmap(self.offscreen as *mut (), self.offscreen.len()); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /common/src/logger.rs: -------------------------------------------------------------------------------- 1 | use redox_log::{OutputBuilder, RedoxLogger}; 2 | 3 | pub fn output_level() -> log::LevelFilter { 4 | //TODO: adjust with bootloader environment 5 | log::LevelFilter::Info 6 | } 7 | 8 | pub fn file_level() -> log::LevelFilter { 9 | log::LevelFilter::Info 10 | } 11 | 12 | /// Configures logging for a single driver. 13 | #[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))] 14 | pub fn setup_logging( 15 | category: &str, 16 | subcategory: &str, 17 | logfile_base: &str, 18 | output_level: log::LevelFilter, 19 | file_level: log::LevelFilter, 20 | ) { 21 | let mut logger = RedoxLogger::new().with_output( 22 | OutputBuilder::stderr() 23 | .with_filter(output_level) // limit global output to important info 24 | .with_ansi_escape_codes() 25 | .flush_on_newline(true) 26 | .build(), 27 | ); 28 | 29 | #[cfg(target_os = "redox")] 30 | match OutputBuilder::in_redox_logging_scheme( 31 | category, 32 | subcategory, 33 | format!("{logfile_base}.log"), 34 | ) { 35 | Ok(b) => { 36 | logger = logger.with_output(b.with_filter(file_level).flush_on_newline(true).build()) 37 | } 38 | Err(error) => eprintln!("Failed to create {logfile_base}.log: {}", error), 39 | } 40 | 41 | #[cfg(target_os = "redox")] 42 | match OutputBuilder::in_redox_logging_scheme( 43 | category, 44 | subcategory, 45 | format!("{logfile_base}.ansi.log"), 46 | ) { 47 | Ok(b) => { 48 | logger = logger.with_output( 49 | b.with_filter(file_level) 50 | .with_ansi_escape_codes() 51 | .flush_on_newline(true) 52 | .build(), 53 | ) 54 | } 55 | Err(error) => eprintln!("Failed to create {logfile_base}.ansi.log: {}", error), 56 | } 57 | 58 | logger.enable().expect("failed to set default logger"); 59 | } 60 | -------------------------------------------------------------------------------- /usb/xhcid/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The eXtensible Host Controller Interface (XHCI) Daemon Interface 2 | //! 3 | //! This crate implements the driver interface for interacting with the Redox xhcid daemon from 4 | //! another userspace process. 5 | //! 6 | //! XHCI is a standard for the USB Host Controller interface specified by Intel that provides a 7 | //! common register interface for systems to use to interact with the Universal Serial Bus (USB) 8 | //! subsystem. 9 | //! 10 | //! USB consists of three types of devices: The Host Controller/Root Hub, USB Hubs, and Endpoints. 11 | //! Endpoints represent actual devices connected to the USB fabric. USB Hubs are intermediaries 12 | //! between the Host Controller and the endpoints that report when devices have been connected/disconnected. 13 | //! The Host Controller provides the interface to the USB subsystem that software running on the 14 | //! system's CPU can interact with. It's a tree-like structure, which the Host Controller enumerating 15 | //! and addressing all the hubs and endpoints in the tree. Data then flows through the fabric 16 | //! using the USB protocol (2.0 or 3.2) as packets. Hubs have multiple ports that endpoints can 17 | //! connect to, and they notify the Host Controller/Root Hub when devices are hot plugged or removed. 18 | //! 19 | //! This documentation will refer directly to the relevant standards, which are as follows: 20 | //! 21 | //! - XHCI - [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf) 22 | //! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) 23 | //! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) 24 | //! 25 | pub extern crate plain; 26 | 27 | mod driver_interface; 28 | pub mod usb; 29 | 30 | pub use driver_interface::*; 31 | -------------------------------------------------------------------------------- /pcid/src/driver_interface/bar.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | // This type is used instead of [pci_types::Bar] in the driver interface as the 6 | // latter can't be serialized and is missing the convenience functions of [PciBar]. 7 | #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] 8 | pub enum PciBar { 9 | None, 10 | Memory32 { addr: u32, size: u32 }, 11 | Memory64 { addr: u64, size: u64 }, 12 | Port(u16), 13 | } 14 | 15 | impl PciBar { 16 | pub fn display(&self) -> String { 17 | match self { 18 | PciBar::None => format!(""), 19 | PciBar::Memory32 { addr, .. } => format!("{addr:08X}"), 20 | PciBar::Memory64 { addr, .. } => format!("{addr:016X}"), 21 | PciBar::Port(port) => format!("P{port:04X}"), 22 | } 23 | } 24 | 25 | pub fn is_none(&self) -> bool { 26 | match self { 27 | &PciBar::None => true, 28 | _ => false, 29 | } 30 | } 31 | 32 | pub fn expect_port(&self) -> u16 { 33 | match *self { 34 | PciBar::Port(port) => port, 35 | PciBar::Memory32 { .. } | PciBar::Memory64 { .. } => { 36 | panic!("expected port BAR, found memory BAR"); 37 | } 38 | PciBar::None => panic!("expected BAR to exist"), 39 | } 40 | } 41 | 42 | pub fn expect_mem(&self) -> (usize, usize) { 43 | match *self { 44 | PciBar::Memory32 { addr, size } => (addr as usize, size as usize), 45 | PciBar::Memory64 { addr, size } => ( 46 | addr.try_into() 47 | .expect("conversion from 64bit BAR to usize failed"), 48 | size.try_into() 49 | .expect("conversion from 64bit BAR size to usize failed"), 50 | ), 51 | PciBar::Port(_) => panic!("expected memory BAR, found port BAR"), 52 | PciBar::None => panic!("expected BAR to exist"), 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /storage/usbscsid/src/protocol/mod.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::num::NonZeroU32; 3 | 4 | use thiserror::Error; 5 | use xhcid_interface::{ 6 | ConfDesc, DevDesc, DeviceReqData, IfDesc, XhciClientHandle, XhciClientHandleError, 7 | }; 8 | 9 | #[derive(Debug, Error)] 10 | pub enum ProtocolError { 11 | #[error("Too large command block ({0} > 16)")] 12 | TooLargeCommandBlock(usize), 13 | 14 | #[error("xhcid connection error: {0}")] 15 | XhciError(#[from] XhciClientHandleError), 16 | 17 | #[error("i/o error")] 18 | IoError(#[from] io::Error), 19 | 20 | #[error("attempted recovery failed")] 21 | RecoveryFailed, 22 | 23 | #[error("protocol error")] 24 | ProtocolError(&'static str), 25 | } 26 | 27 | #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] 28 | pub struct SendCommandStatus { 29 | pub residue: Option, 30 | pub kind: SendCommandStatusKind, 31 | } 32 | 33 | impl SendCommandStatus { 34 | pub fn bytes_transferred(&self, transfer_len: u32) -> u32 { 35 | transfer_len - self.residue.map(u32::from).unwrap_or(0) 36 | } 37 | } 38 | 39 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 40 | pub enum SendCommandStatusKind { 41 | Success, 42 | Failed, 43 | } 44 | 45 | impl Default for SendCommandStatusKind { 46 | fn default() -> Self { 47 | Self::Success 48 | } 49 | } 50 | 51 | pub trait Protocol { 52 | fn send_command( 53 | &mut self, 54 | command: &[u8], 55 | data: DeviceReqData, 56 | ) -> Result; 57 | } 58 | 59 | /// Bulk-only transport 60 | pub mod bot; 61 | 62 | mod uas { 63 | // TODO 64 | } 65 | 66 | use bot::BulkOnlyTransport; 67 | 68 | pub fn setup<'a>( 69 | handle: &'a XhciClientHandle, 70 | protocol: u8, 71 | dev_desc: &DevDesc, 72 | conf_desc: &ConfDesc, 73 | if_desc: &IfDesc, 74 | ) -> Option> { 75 | match protocol { 76 | 0x50 => Some(Box::new( 77 | BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap(), 78 | )), 79 | _ => None, 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /virtio-core/src/utils.rs: -------------------------------------------------------------------------------- 1 | use core::cell::UnsafeCell; 2 | use core::fmt::Debug; 3 | use core::marker::PhantomData; 4 | 5 | #[repr(C)] 6 | pub struct VolatileCell { 7 | value: UnsafeCell, 8 | } 9 | 10 | impl VolatileCell { 11 | #[inline] 12 | pub const fn new(value: T) -> Self { 13 | Self { 14 | value: UnsafeCell::new(value), 15 | } 16 | } 17 | 18 | /// Returns a copy of the contained value. 19 | #[inline] 20 | pub fn get(&self) -> T { 21 | unsafe { core::ptr::read_volatile(self.value.get()) } 22 | } 23 | 24 | /// Sets the contained value. 25 | #[inline] 26 | pub fn set(&mut self, value: T) { 27 | unsafe { core::ptr::write_volatile(self.value.get(), value) } 28 | } 29 | } 30 | 31 | impl Debug for VolatileCell 32 | where 33 | T: Debug + Copy, 34 | { 35 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 36 | f.debug_struct("VolatileCell") 37 | .field("value", &self.get()) 38 | .finish() 39 | } 40 | } 41 | 42 | unsafe impl Sync for VolatileCell {} 43 | 44 | #[repr(C)] 45 | pub struct IncompleteArrayField(PhantomData, [T; 0]); 46 | 47 | impl IncompleteArrayField { 48 | #[inline] 49 | pub const fn new() -> Self { 50 | IncompleteArrayField(PhantomData, []) 51 | } 52 | 53 | #[inline] 54 | pub unsafe fn as_slice(&self, len: usize) -> &[T] { 55 | core::slice::from_raw_parts(self.as_ptr(), len) 56 | } 57 | 58 | #[inline] 59 | pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { 60 | core::slice::from_raw_parts_mut(self.as_mut_ptr(), len) 61 | } 62 | 63 | #[inline] 64 | pub unsafe fn as_ptr(&self) -> *const T { 65 | self as *const _ as *const T 66 | } 67 | 68 | #[inline] 69 | pub unsafe fn as_mut_ptr(&mut self) -> *mut T { 70 | self as *mut _ as *mut T 71 | } 72 | } 73 | 74 | pub const fn align(val: usize, align: usize) -> usize { 75 | (val + align) & !align 76 | } 77 | 78 | pub const fn align_down(addr: usize) -> usize { 79 | addr & !(syscall::PAGE_SIZE - 1) 80 | } 81 | -------------------------------------------------------------------------------- /usb/usbctl/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use xhcid_interface::{PortId, XhciClientHandle}; 3 | 4 | fn main() { 5 | let matches = App::new("usbctl") 6 | .arg( 7 | Arg::with_name("SCHEME") 8 | .takes_value(true) 9 | .required(true) 10 | .long("scheme") 11 | .short("s"), 12 | ) 13 | .subcommand( 14 | App::new("port") 15 | .arg(Arg::with_name("PORT").takes_value(true).required(true)) 16 | .subcommand(App::new("status")) 17 | .subcommand( 18 | App::new("endpoint") 19 | .arg( 20 | Arg::with_name("ENDPOINT_NUM") 21 | .takes_value(true) 22 | .required(true), 23 | ) 24 | .subcommand(App::new("status")), 25 | ), 26 | ) 27 | .get_matches(); 28 | 29 | let scheme = matches.value_of("SCHEME").expect("no scheme"); 30 | 31 | if let Some(port_scmd_matches) = matches.subcommand_matches("port") { 32 | let port = port_scmd_matches 33 | .value_of("PORT") 34 | .expect("invalid utf-8 for PORT argument") 35 | .parse::() 36 | .expect("expected PORT ID"); 37 | 38 | let handle = XhciClientHandle::new(scheme.to_owned(), port); 39 | 40 | if let Some(_status_scmd_matches) = port_scmd_matches.subcommand_matches("status") { 41 | let state = handle.port_state().expect("Failed to get port state"); 42 | println!("{}", state.as_str()); 43 | } else if let Some(endp_scmd_matches) = port_scmd_matches.subcommand_matches("endpoint") { 44 | let endp_num = endp_scmd_matches 45 | .value_of("ENDPOINT_NUM") 46 | .expect("no valid ENDPOINT_NUM") 47 | .parse::() 48 | .expect("expected ENDPOINT_NUM to be an 8-bit integer"); 49 | let mut endp_handle = handle 50 | .open_endpoint(endp_num) 51 | .expect("Failed to open endpoint"); 52 | let state = endp_handle.status().expect("Failed to get endpoint state"); 53 | println!("{}", state.as_str()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /common/src/io/pio.rs: -------------------------------------------------------------------------------- 1 | use core::{arch::asm, marker::PhantomData}; 2 | 3 | use super::Io; 4 | 5 | /// Generic PIO 6 | #[derive(Copy, Clone)] 7 | pub struct Pio { 8 | port: u16, 9 | value: PhantomData, 10 | } 11 | 12 | impl Pio { 13 | /// Create a PIO from a given port 14 | pub const fn new(port: u16) -> Self { 15 | Pio:: { 16 | port, 17 | value: PhantomData, 18 | } 19 | } 20 | } 21 | 22 | /// Read/Write for byte PIO 23 | impl Io for Pio { 24 | type Value = u8; 25 | 26 | /// Read 27 | #[inline(always)] 28 | fn read(&self) -> u8 { 29 | let value: u8; 30 | unsafe { 31 | asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags)); 32 | } 33 | value 34 | } 35 | 36 | /// Write 37 | #[inline(always)] 38 | fn write(&mut self, value: u8) { 39 | unsafe { 40 | asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags)); 41 | } 42 | } 43 | } 44 | 45 | /// Read/Write for word PIO 46 | impl Io for Pio { 47 | type Value = u16; 48 | 49 | /// Read 50 | #[inline(always)] 51 | fn read(&self) -> u16 { 52 | let value: u16; 53 | unsafe { 54 | asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags)); 55 | } 56 | value 57 | } 58 | 59 | /// Write 60 | #[inline(always)] 61 | fn write(&mut self, value: u16) { 62 | unsafe { 63 | asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags)); 64 | } 65 | } 66 | } 67 | 68 | /// Read/Write for doubleword PIO 69 | impl Io for Pio { 70 | type Value = u32; 71 | 72 | /// Read 73 | #[inline(always)] 74 | fn read(&self) -> u32 { 75 | let value: u32; 76 | unsafe { 77 | asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags)); 78 | } 79 | value 80 | } 81 | 82 | /// Write 83 | #[inline(always)] 84 | fn write(&mut self, value: u32) { 85 | unsafe { 86 | asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags)); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /hwd/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::process; 2 | 3 | mod backend; 4 | use self::backend::{AcpiBackend, Backend, DeviceTreeBackend, LegacyBackend}; 5 | 6 | fn daemon(daemon: redox_daemon::Daemon) -> ! { 7 | common::setup_logging( 8 | "misc", 9 | "hwd", 10 | "hwd", 11 | common::output_level(), 12 | common::file_level(), 13 | ); 14 | 15 | // Prefer DTB if available (matches kernel preference) 16 | let mut backend: Box = match DeviceTreeBackend::new() { 17 | Ok(ok) => { 18 | log::info!("using devicetree backend"); 19 | Box::new(ok) 20 | } 21 | Err(err) => { 22 | log::debug!("cannot use devicetree backend: {}", err); 23 | match AcpiBackend::new() { 24 | Ok(ok) => { 25 | log::info!("using ACPI backend"); 26 | Box::new(ok) 27 | } 28 | Err(err) => { 29 | log::debug!("cannot use ACPI backend: {}", err); 30 | 31 | log::info!("using legacy backend"); 32 | Box::new(LegacyBackend) 33 | } 34 | } 35 | } 36 | }; 37 | 38 | //TODO: launch pcid based on backend information? 39 | // Must launch after acpid but before probe calls /scheme/acpi/symbols 40 | match process::Command::new("pcid").spawn() { 41 | Ok(mut child) => match child.wait() { 42 | Ok(status) => if !status.success() { 43 | log::error!("pcid exited with status {}", status); 44 | }, 45 | Err(err) => { 46 | log::error!("failed to wait for pcid: {}", err); 47 | } 48 | }, 49 | Err(err) => { 50 | log::error!("failed to spawn pcid: {}", err); 51 | } 52 | } 53 | 54 | daemon.ready().expect("hwd: failed to notify parent"); 55 | 56 | //TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers 57 | match backend.probe() { 58 | Ok(()) => { 59 | process::exit(0); 60 | } 61 | Err(err) => { 62 | log::error!("failed to probe with error {}", err); 63 | process::exit(1); 64 | } 65 | } 66 | } 67 | 68 | fn main() { 69 | redox_daemon::Daemon::new(daemon).expect("hwd: failed to daemonize"); 70 | } -------------------------------------------------------------------------------- /graphics/bgad/src/main.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use inputd::ProducerHandle; 4 | use pcid_interface::PciFunctionHandle; 5 | use redox_scheme::{RequestKind, SignalBehavior, Socket}; 6 | 7 | use crate::bga::Bga; 8 | use crate::scheme::BgaScheme; 9 | 10 | mod bga; 11 | mod scheme; 12 | 13 | // FIXME add a driver-graphics implementation 14 | 15 | fn main() { 16 | let mut pcid_handle = PciFunctionHandle::connect_default(); 17 | let pci_config = pcid_handle.config(); 18 | 19 | let mut name = pci_config.func.name(); 20 | name.push_str("_bga"); 21 | 22 | common::setup_logging( 23 | "graphics", 24 | "pci", 25 | &name, 26 | common::output_level(), 27 | common::file_level(), 28 | ); 29 | 30 | log::info!("BGA {}", pci_config.func.display()); 31 | 32 | redox_daemon::Daemon::new(move |daemon| { 33 | let socket = Socket::create("bga").expect("bgad: failed to create bga scheme"); 34 | 35 | let bar = unsafe { pcid_handle.map_bar(2) }.ptr.as_ptr(); 36 | 37 | let mut bga = unsafe { Bga::new(bar) }; 38 | log::debug!("BGA {}x{}", bga.width(), bga.height()); 39 | 40 | let mut scheme = BgaScheme { 41 | bga, 42 | display: ProducerHandle::new().ok(), 43 | }; 44 | 45 | scheme.update_size(); 46 | 47 | libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace"); 48 | 49 | daemon.ready().expect("bgad: failed to notify parent"); 50 | 51 | loop { 52 | let Some(request) = socket 53 | .next_request(SignalBehavior::Restart) 54 | .expect("bgad: failed to get next scheme request") 55 | else { 56 | // Scheme likely got unmounted 57 | std::process::exit(0); 58 | }; 59 | match request.kind() { 60 | RequestKind::Call(call) => { 61 | let response = call.handle_sync(&mut scheme); 62 | 63 | socket 64 | .write_response(response, SignalBehavior::Restart) 65 | .expect("bgad: failed to write next scheme response"); 66 | } 67 | RequestKind::OnClose { id } => { 68 | scheme.on_close(id); 69 | } 70 | _ => (), 71 | } 72 | } 73 | }) 74 | .expect("bgad: failed to daemonize"); 75 | } 76 | -------------------------------------------------------------------------------- /common/src/io.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | cmp::PartialEq, 3 | ops::{BitAnd, BitOr, Not}, 4 | }; 5 | 6 | mod mmio; 7 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 8 | mod pio; 9 | 10 | pub use mmio::*; 11 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 12 | pub use pio::*; 13 | 14 | /// IO abstraction 15 | pub trait Io { 16 | /// Value type for IO, usually some unsigned number 17 | type Value: Copy 18 | + PartialEq 19 | + BitAnd 20 | + BitOr 21 | + Not; 22 | 23 | /// Read the underlying valu2e 24 | fn read(&self) -> Self::Value; 25 | /// Write the underlying value 26 | fn write(&mut self, value: Self::Value); 27 | 28 | /// Check whether the underlying value contains bit flags 29 | #[inline(always)] 30 | fn readf(&self, flags: Self::Value) -> bool { 31 | (self.read() & flags) as Self::Value == flags 32 | } 33 | 34 | /// Enable or disable specific bit flags 35 | #[inline(always)] 36 | fn writef(&mut self, flags: Self::Value, value: bool) { 37 | let tmp: Self::Value = match value { 38 | true => self.read() | flags, 39 | false => self.read() & !flags, 40 | }; 41 | self.write(tmp); 42 | } 43 | } 44 | 45 | /// Read-only IO 46 | #[repr(transparent)] 47 | pub struct ReadOnly { 48 | inner: I, 49 | } 50 | 51 | impl ReadOnly { 52 | /// Wraps IO 53 | pub const fn new(inner: I) -> ReadOnly { 54 | ReadOnly { inner } 55 | } 56 | } 57 | 58 | impl ReadOnly { 59 | /// Calls [Io::read] 60 | #[inline(always)] 61 | pub fn read(&self) -> I::Value { 62 | self.inner.read() 63 | } 64 | 65 | /// Calls [Io::readf] 66 | #[inline(always)] 67 | pub fn readf(&self, flags: I::Value) -> bool { 68 | self.inner.readf(flags) 69 | } 70 | } 71 | 72 | #[repr(transparent)] 73 | /// Write-only IO 74 | pub struct WriteOnly { 75 | inner: I, 76 | } 77 | 78 | impl WriteOnly { 79 | /// Wraps IO 80 | pub const fn new(inner: I) -> WriteOnly { 81 | WriteOnly { inner } 82 | } 83 | } 84 | 85 | impl WriteOnly { 86 | /// Calls [Io::write] 87 | #[inline(always)] 88 | pub fn write(&mut self, value: I::Value) { 89 | self.inner.write(value) 90 | } 91 | 92 | #[inline(always)] 93 | /// Calls [Io::writef] 94 | pub fn writef(&mut self, flags: I::Value, value: bool) { 95 | self.inner.writef(flags, value) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /usb/xhcid/src/usb/endpoint.rs: -------------------------------------------------------------------------------- 1 | use plain::Plain; 2 | 3 | /// The descriptor for a USB Endpoint. 4 | /// 5 | /// Each endpoint for a particular interface has its own descriptor. The information in this 6 | /// structure is used by the host to determine the bandwidth requirements of the endpoint. 7 | /// 8 | /// This is returned automatically when you send a request for a ConfigurationDescriptor, 9 | /// and cannot be requested individually. 10 | /// 11 | /// See USB32 9.6.6 12 | /// 13 | /// The offsets for the fields in the packet are described in USB32 Table 9-26 14 | #[repr(C, packed)] 15 | #[derive(Clone, Copy, Debug, Default)] 16 | pub struct EndpointDescriptor { 17 | pub length: u8, 18 | pub kind: u8, 19 | pub address: u8, 20 | pub attributes: u8, 21 | pub max_packet_size: u16, 22 | pub interval: u8, 23 | } 24 | 25 | /// Mask that is ANDed to the [EndpointDescriptor].attributes buffer to get the endpoint type. 26 | pub const ENDP_ATTR_TY_MASK: u8 = 0x3; 27 | 28 | #[repr(u8)] 29 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 30 | pub enum EndpointTy { 31 | Ctrl = 0, 32 | Isoch = 1, 33 | Bulk = 2, 34 | Interrupt = 3, 35 | } 36 | 37 | impl EndpointDescriptor { 38 | fn ty(self) -> EndpointTy { 39 | match self.attributes & ENDP_ATTR_TY_MASK { 40 | 0 => EndpointTy::Ctrl, 41 | 1 => EndpointTy::Isoch, 42 | 2 => EndpointTy::Bulk, 43 | 3 => EndpointTy::Interrupt, 44 | _ => unreachable!(), 45 | } 46 | } 47 | } 48 | 49 | unsafe impl Plain for EndpointDescriptor {} 50 | 51 | #[repr(C, packed)] 52 | #[derive(Clone, Copy, Debug, Default)] 53 | pub struct SuperSpeedCompanionDescriptor { 54 | pub length: u8, 55 | pub kind: u8, 56 | pub max_burst: u8, 57 | pub attributes: u8, 58 | pub bytes_per_interval: u16, 59 | } 60 | unsafe impl Plain for SuperSpeedCompanionDescriptor {} 61 | 62 | #[repr(C, packed)] 63 | #[derive(Clone, Copy, Debug, Default)] 64 | pub struct SuperSpeedPlusIsochCmpDescriptor { 65 | pub length: u8, 66 | pub kind: u8, 67 | pub reserved: u16, 68 | pub bytes_per_interval: u32, 69 | } 70 | unsafe impl Plain for SuperSpeedPlusIsochCmpDescriptor {} 71 | 72 | #[repr(C, packed)] 73 | #[derive(Clone, Copy, Debug, Default)] 74 | pub struct HidDescriptor { 75 | pub length: u8, 76 | pub kind: u8, 77 | pub hid_spec_release: u16, 78 | pub country_code: u8, 79 | pub num_descriptors: u8, 80 | pub report_desc_ty: u8, 81 | pub report_desc_len: u16, 82 | pub optional_desc_ty: u8, 83 | pub optional_desc_len: u16, 84 | } 85 | 86 | unsafe impl Plain for HidDescriptor {} 87 | -------------------------------------------------------------------------------- /storage/ahcid/src/ahci/mod.rs: -------------------------------------------------------------------------------- 1 | use common::io::Io; 2 | use driver_block::Disk; 3 | use log::{error, info}; 4 | 5 | use self::disk_ata::DiskATA; 6 | use self::disk_atapi::DiskATAPI; 7 | use self::hba::{HbaMem, HbaPortType}; 8 | 9 | pub mod disk_ata; 10 | pub mod disk_atapi; 11 | pub mod fis; 12 | pub mod hba; 13 | 14 | pub enum AnyDisk { 15 | Ata(DiskATA), 16 | Atapi(DiskATAPI), 17 | } 18 | impl Disk for AnyDisk { 19 | fn block_size(&self) -> u32 { 20 | match self { 21 | Self::Ata(a) => a.block_size(), 22 | Self::Atapi(a) => a.block_size(), 23 | } 24 | } 25 | fn size(&self) -> u64 { 26 | match self { 27 | Self::Ata(a) => a.size(), 28 | Self::Atapi(a) => a.size(), 29 | } 30 | } 31 | async fn read(&mut self, base: u64, buffer: &mut [u8]) -> syscall::Result { 32 | match self { 33 | Self::Ata(a) => a.read(base, buffer).await, 34 | Self::Atapi(a) => a.read(base, buffer).await, 35 | } 36 | } 37 | async fn write(&mut self, base: u64, buffer: &[u8]) -> syscall::Result { 38 | match self { 39 | Self::Ata(a) => a.write(base, buffer).await, 40 | Self::Atapi(a) => a.write(base, buffer).await, 41 | } 42 | } 43 | } 44 | 45 | pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec) { 46 | let hba_mem = unsafe { &mut *(base as *mut HbaMem) }; 47 | hba_mem.init(); 48 | let pi = hba_mem.pi.read(); 49 | let disks: Vec = (0..hba_mem.ports.len()) 50 | .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) 51 | .filter_map(|i| { 52 | let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; 53 | let port_type = port.probe(); 54 | info!("{}-{}: {:?}", name, i, port_type); 55 | 56 | let disk: Option = match port_type { 57 | HbaPortType::SATA => match DiskATA::new(i, port) { 58 | Ok(disk) => Some(AnyDisk::Ata(disk)), 59 | Err(err) => { 60 | error!("{}: {}", i, err); 61 | None 62 | } 63 | }, 64 | HbaPortType::SATAPI => match DiskATAPI::new(i, port) { 65 | Ok(disk) => Some(AnyDisk::Atapi(disk)), 66 | Err(err) => { 67 | error!("{}: {}", i, err); 68 | None 69 | } 70 | }, 71 | _ => None, 72 | }; 73 | 74 | disk 75 | }) 76 | .collect(); 77 | 78 | (hba_mem, disks) 79 | } 80 | -------------------------------------------------------------------------------- /pcid/src/driver_interface/config.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | use std::ops::Range; 3 | 4 | use serde::Deserialize; 5 | 6 | use crate::driver_interface::FullDeviceId; 7 | 8 | #[derive(Clone, Debug, Default, Deserialize)] 9 | pub struct Config { 10 | pub drivers: Vec, 11 | } 12 | 13 | #[derive(Clone, Debug, Default, Deserialize)] 14 | pub struct DriverConfig { 15 | pub name: Option, 16 | pub class: Option, 17 | pub subclass: Option, 18 | pub interface: Option, 19 | pub ids: Option>>, 20 | pub vendor: Option, 21 | pub device: Option, 22 | pub device_id_range: Option>, 23 | pub command: Vec, 24 | } 25 | 26 | impl DriverConfig { 27 | pub fn match_function(&self, id: &FullDeviceId) -> bool { 28 | if let Some(class) = self.class { 29 | if class != id.class { 30 | return false; 31 | } 32 | } 33 | 34 | if let Some(subclass) = self.subclass { 35 | if subclass != id.subclass { 36 | return false; 37 | } 38 | } 39 | 40 | if let Some(interface) = self.interface { 41 | if interface != id.interface { 42 | return false; 43 | } 44 | } 45 | 46 | if let Some(ref ids) = self.ids { 47 | let mut device_found = false; 48 | for (vendor, devices) in ids { 49 | let vendor_without_prefix = vendor.trim_start_matches("0x"); 50 | let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; 51 | 52 | if vendor != id.vendor_id { 53 | continue; 54 | } 55 | 56 | for device in devices { 57 | if *device == id.device_id { 58 | device_found = true; 59 | break; 60 | } 61 | } 62 | } 63 | if !device_found { 64 | return false; 65 | } 66 | } else { 67 | if let Some(vendor) = self.vendor { 68 | if vendor != id.vendor_id { 69 | return false; 70 | } 71 | } 72 | 73 | if let Some(device) = self.device { 74 | if device != id.device_id { 75 | return false; 76 | } 77 | } 78 | } 79 | 80 | if let Some(ref device_id_range) = self.device_id_range { 81 | if id.device_id < device_id_range.start || device_id_range.end <= id.device_id { 82 | return false; 83 | } 84 | } 85 | 86 | true 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /storage/nvmed/src/nvme/executor.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::fs::File; 3 | use std::rc::Rc; 4 | use std::sync::Arc; 5 | 6 | use executor::{Hardware, LocalExecutor}; 7 | 8 | use super::{CmdId, CqId, Nvme, NvmeCmd, NvmeComp, SqId}; 9 | 10 | pub struct NvmeHw; 11 | 12 | impl Hardware for NvmeHw { 13 | type Iv = u16; 14 | type Sqe = NvmeCmd; 15 | type Cqe = NvmeComp; 16 | type CmdId = CmdId; 17 | type CqId = CqId; 18 | type SqId = SqId; 19 | type GlobalCtxt = Arc; 20 | 21 | fn mask_vector(ctxt: &Arc, iv: Self::Iv) { 22 | ctxt.set_vector_masked(iv, true) 23 | } 24 | fn unmask_vector(ctxt: &Arc, iv: Self::Iv) { 25 | ctxt.set_vector_masked(iv, false) 26 | } 27 | fn set_sqe_cmdid(sqe: &mut NvmeCmd, id: CmdId) { 28 | sqe.cid = id; 29 | } 30 | fn get_cqe_cmdid(cqe: &Self::Cqe) -> Self::CmdId { 31 | cqe.cid 32 | } 33 | fn vtable() -> &'static std::task::RawWakerVTable { 34 | &VTABLE 35 | } 36 | fn current() -> std::rc::Rc> { 37 | THE_EXECUTOR.with(|exec| Rc::clone(exec.borrow().as_ref().unwrap())) 38 | } 39 | fn try_submit( 40 | nvme: &Arc, 41 | sq_id: Self::SqId, 42 | success: impl FnOnce(Self::CmdId) -> Self::Sqe, 43 | fail: impl FnOnce(), 44 | ) -> Option<(Self::CqId, Self::CmdId)> { 45 | let ctxt = nvme.cur_thread_ctxt(); 46 | let ctxt = ctxt.lock(); 47 | 48 | nvme.try_submit_raw(&*ctxt, sq_id, success, fail) 49 | } 50 | fn poll_cqes(nvme: &Arc, mut handle: impl FnMut(Self::CqId, Self::Cqe)) { 51 | let ctxt = nvme.cur_thread_ctxt(); 52 | let ctxt = ctxt.lock(); 53 | 54 | for (sq_cq_id, (sq, cq)) in ctxt.queues.borrow_mut().iter_mut() { 55 | while let Some((new_head, cqe)) = cq.complete() { 56 | unsafe { 57 | nvme.completion_queue_head(*sq_cq_id, new_head); 58 | } 59 | sq.head = cqe.sq_head; 60 | log::trace!("new head {new_head} cqe {cqe:?}"); 61 | handle(*sq_cq_id, cqe); 62 | } 63 | } 64 | } 65 | fn sq_cq(_ctxt: &Arc, id: Self::CqId) -> Self::SqId { 66 | id 67 | } 68 | } 69 | 70 | static VTABLE: std::task::RawWakerVTable = executor::vtable::(); 71 | 72 | thread_local! { 73 | static THE_EXECUTOR: RefCell>>> = RefCell::new(None); 74 | } 75 | 76 | pub type NvmeExecutor = LocalExecutor; 77 | 78 | pub fn init(nvme: Arc, iv: u16, intx: bool, irq_handle: File) -> Rc> { 79 | let this = Rc::new(executor::init_raw(nvme, iv, intx, irq_handle)); 80 | THE_EXECUTOR.with(|exec| *exec.borrow_mut() = Some(Rc::clone(&this))); 81 | this 82 | } 83 | -------------------------------------------------------------------------------- /virtio-core/src/spec/mod.rs: -------------------------------------------------------------------------------- 1 | //! https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html 2 | //! 3 | //! This file contains comments copied from the VirtIO specification which are 4 | //! licensed under the following conditions: 5 | //! 6 | //! Copyright © OASIS Open 2022. All Rights Reserved. 7 | //! 8 | //! All capitalized terms in the following text have the meanings assigned to them 9 | //! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The 10 | //! full Policy may be found at the OASIS website. 11 | //! 12 | //! This document and translations of it may be copied and furnished to others, 13 | //! and derivative works that comment on or otherwise explain it or assist in its 14 | //! implementation may be prepared, copied, published, and distributed, in whole 15 | //! or in part, without restriction of any kind, provided that the above copyright 16 | //! notice and this section are included on all such copies and derivative works. 17 | //! However, this document itself may not be modified in any way, including by 18 | //! removing the copyright notice or references to OASIS, except as needed for the 19 | //! purpose of developing any document or deliverable produced by an OASIS Technical 20 | //! Committee (in which case the rules applicable to copyrights, as set forth in the 21 | //! OASIS IPR Policy, must be followed) or as required to translate it into languages 22 | //! other than English. 23 | 24 | bitflags::bitflags! { 25 | /// [2.1 Device Status Field](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-110001) 26 | #[derive(Debug, Copy, Clone, PartialEq)] 27 | #[repr(transparent)] 28 | pub struct DeviceStatusFlags: u8 { 29 | /// Indicates that the guest OS has found the device and recognized it as a 30 | /// valid device. 31 | const ACKNOWLEDGE = 1; 32 | /// Indicates that the guest OS knows how to drive the device. 33 | const DRIVER = 2; 34 | /// Indicates that something went wrong in the guest and it has given up on 35 | /// the device. 36 | const FAILED = 128; 37 | /// Indicates that the driver has acknowledged all the features it understands 38 | /// and feature negotiation is complete. 39 | const FEATURES_OK = 8; 40 | /// Indicates that the driver is set up and ready to drive the device. 41 | const DRIVER_OK = 4; 42 | /// Indicates that the device has experienced an error from which it can’t recover. 43 | const DEVICE_NEEDS_RESET = 64; 44 | } 45 | } 46 | 47 | mod split_virtqueue; 48 | pub use split_virtqueue::*; 49 | 50 | // FIXME add [2.8 Packed Virtqueues](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-720008) 51 | 52 | mod transport_pci; 53 | pub use transport_pci::*; 54 | 55 | mod reserved_features; 56 | pub use reserved_features::*; 57 | -------------------------------------------------------------------------------- /net/ixgbed/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Read, Write}; 2 | use std::os::unix::io::AsRawFd; 3 | 4 | use driver_network::NetworkScheme; 5 | use event::{user_data, EventQueue}; 6 | use pcid_interface::PciFunctionHandle; 7 | 8 | pub mod device; 9 | #[rustfmt::skip] 10 | mod ixgbe; 11 | 12 | fn main() { 13 | let mut pcid_handle = PciFunctionHandle::connect_default(); 14 | let pci_config = pcid_handle.config(); 15 | 16 | let mut name = pci_config.func.name(); 17 | name.push_str("_ixgbe"); 18 | 19 | let irq = pci_config 20 | .func 21 | .legacy_interrupt_line 22 | .expect("ixgbed: no legacy interrupts supported"); 23 | 24 | println!(" + IXGBE {}", pci_config.func.display()); 25 | 26 | redox_daemon::Daemon::new(move |daemon| { 27 | let mut irq_file = irq.irq_handle("ixgbed"); 28 | 29 | let mapped_bar = unsafe { pcid_handle.map_bar(0) }; 30 | let address = mapped_bar.ptr.as_ptr(); 31 | let size = mapped_bar.bar_size; 32 | 33 | let mut scheme = NetworkScheme::new( 34 | move || { 35 | device::Intel8259x::new(address as usize, size) 36 | .expect("ixgbed: failed to allocate device") 37 | }, 38 | daemon, 39 | format!("network.{name}"), 40 | ); 41 | 42 | user_data! { 43 | enum Source { 44 | Irq, 45 | Scheme, 46 | } 47 | } 48 | 49 | let event_queue = 50 | EventQueue::::new().expect("ixgbed: Could not create event queue."); 51 | event_queue 52 | .subscribe( 53 | irq_file.as_raw_fd() as usize, 54 | Source::Irq, 55 | event::EventFlags::READ, 56 | ) 57 | .unwrap(); 58 | event_queue 59 | .subscribe( 60 | scheme.event_handle().raw(), 61 | Source::Scheme, 62 | event::EventFlags::READ, 63 | ) 64 | .unwrap(); 65 | 66 | libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); 67 | 68 | scheme.tick().unwrap(); 69 | 70 | for event in event_queue.map(|e| e.expect("ixgbed: failed to get next event")) { 71 | match event.user_data { 72 | Source::Irq => { 73 | let mut irq = [0; 8]; 74 | irq_file.read(&mut irq).unwrap(); 75 | if scheme.adapter().irq() { 76 | irq_file.write(&mut irq).unwrap(); 77 | 78 | scheme.tick().unwrap(); 79 | } 80 | } 81 | Source::Scheme => { 82 | scheme.tick().unwrap(); 83 | } 84 | } 85 | } 86 | unreachable!() 87 | }) 88 | .expect("ixgbed: failed to create daemon"); 89 | } 90 | -------------------------------------------------------------------------------- /storage/partitionlib/src/partition.rs: -------------------------------------------------------------------------------- 1 | pub use gpt::disk::LogicalBlockSize; 2 | use std::io::{self, Read, Seek}; 3 | use uuid::Uuid; 4 | 5 | /// A union of the MBR and GPT partition entry 6 | #[derive(Clone, Debug, Eq, Hash, PartialEq)] 7 | pub struct Partition { 8 | /// The starting logical block number 9 | pub start_lba: u64, 10 | /// The size of the partition in sectors 11 | pub size: u64, 12 | pub flags: Option, 13 | pub name: Option, 14 | pub uuid: Option, 15 | } 16 | 17 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 18 | pub enum PartitionTableKind { 19 | Mbr, 20 | Gpt, 21 | } 22 | 23 | #[derive(Clone, Debug, Eq, PartialEq)] 24 | pub struct PartitionTable { 25 | pub partitions: Vec, 26 | pub kind: PartitionTableKind, 27 | } 28 | 29 | fn get_gpt_partitions( 30 | device: &mut D, 31 | sector_size: LogicalBlockSize, 32 | ) -> io::Result { 33 | let header = gpt::header::read_header_from_arbitrary_device(device, sector_size)?; 34 | Ok(PartitionTable { 35 | partitions: gpt::partition::file_read_partitions(device, &header, sector_size).map( 36 | |btree| { 37 | btree 38 | .into_iter() 39 | .map(|(_, part)| Partition { 40 | flags: Some(part.flags), 41 | size: part.last_lba - part.first_lba + 1, 42 | name: Some(part.name.clone()), 43 | uuid: Some(part.part_guid), 44 | start_lba: part.first_lba, 45 | }) 46 | .collect() 47 | }, 48 | )?, 49 | kind: PartitionTableKind::Gpt, 50 | }) 51 | } 52 | fn get_mbr_partitions(device: &mut D) -> io::Result> { 53 | let Some(header) = crate::mbr::read_header(device)? else { 54 | return Ok(None); 55 | }; 56 | Ok(Some(PartitionTable { 57 | kind: PartitionTableKind::Mbr, 58 | partitions: header 59 | .partitions() 60 | .map(|partition: crate::mbr::Entry| Partition { 61 | name: None, 62 | uuid: None, // TODO: Some kind of one-way conversion should be possible 63 | flags: None, // TODO 64 | size: partition.len.into(), 65 | start_lba: partition.rel_sector.into(), 66 | }) 67 | .collect(), 68 | })) 69 | } 70 | pub fn get_partitions( 71 | device: &mut D, 72 | sector_size: LogicalBlockSize, 73 | ) -> io::Result> { 74 | get_gpt_partitions(device, sector_size) 75 | .map(Some) 76 | .or_else(|_| get_mbr_partitions(device)) 77 | } 78 | 79 | impl Partition { 80 | pub fn to_offset(&self, sector_size: LogicalBlockSize) -> u64 { 81 | let blksize: u64 = sector_size.into(); 82 | self.start_lba * blksize 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /usb/xhcid/src/usb/mod.rs: -------------------------------------------------------------------------------- 1 | //! The Universal Serial Bus (USB) Module 2 | //! 3 | //! The implementations in this module are common to all USB interfaces (though individual elements 4 | //! may be specific to only 2.0 or 3.2), and are used by specialized driver components like [xhci] 5 | //! to implement the driver interface. 6 | //! 7 | //! The [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) and the [Universal Serial Bus 3.2 Specification](https://usb.org/document-library/usb-32-revision-11-june-2022) are 8 | //! the documents that inform this implementation. 9 | //! 10 | //! See the crate-level documentation for the acronyms used to refer to specific documents. 11 | pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc}; 12 | pub use self::config::ConfigDescriptor; 13 | pub use self::device::{DeviceDescriptor, DeviceDescriptor8Byte}; 14 | pub use self::endpoint::{ 15 | EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, 16 | SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, 17 | }; 18 | pub use self::hub::*; 19 | pub use self::interface::InterfaceDescriptor; 20 | pub use self::setup::{Setup, SetupReq}; 21 | 22 | /// Enumerates the list of descriptor kinds that can be reported by a USB device to report its 23 | /// attributes to the system. (See USB32 Sections 9.5 and 9.6) 24 | #[derive(Clone, Copy, Debug)] 25 | #[repr(u8)] 26 | pub enum DescriptorKind { 27 | /// No Descriptor TODO: Determine why this state exists, and what it does in the code. 28 | None = 0, 29 | /// A Device Descriptor. See [DeviceDescriptor] 30 | Device = 1, 31 | /// A Configuration Descriptor. See [ConfigDescriptor] 32 | Configuration = 2, 33 | /// A String Descriptor. See (USB32 Section 9.6.9). 34 | String = 3, 35 | /// An Interface Descriptor. See [InterfaceDescriptor] 36 | Interface = 4, 37 | /// An Endpoint Descriptor. See [EndpointDescriptor] 38 | Endpoint = 5, 39 | /// A Device Qualifier. USB2-specific. See [DeviceQualifier] 40 | DeviceQualifier = 6, 41 | /// The "Other Speed Configuration" descriptor. USB2-specific. See (USB2 9.6.4] 42 | OtherSpeedConfiguration = 7, 43 | /// TODO: Determine the standard that specifies this 44 | InterfacePower = 8, 45 | /// TODO: Determine the standard that specifies this (Possibly USB-C?) 46 | OnTheGo = 9, 47 | /// A Binary Device Object Store Descriptor. See [BosDescriptor] 48 | BinaryObjectStorage = 15, 49 | /// TODO: Track down the HID standard for references 50 | Hid = 33, 51 | /// A USB Hub Device Descriptor. See [HubDescriptor] 52 | Hub = 41, 53 | /// A Super Speed Endpoint Companion Descriptor. See [SuperSpeedCompanionDescriptor] 54 | SuperSpeedCompanion = 48, 55 | } 56 | 57 | pub(crate) mod bos; 58 | pub(crate) mod config; 59 | pub(crate) mod device; 60 | pub(crate) mod endpoint; 61 | pub(crate) mod hub; 62 | pub(crate) mod interface; 63 | pub(crate) mod setup; 64 | -------------------------------------------------------------------------------- /storage/usbscsid/src/scsi/opcodes.rs: -------------------------------------------------------------------------------- 1 | #[repr(u8)] 2 | pub enum Opcode { 3 | TestUnitReady = 0x00, 4 | /// obsolete 5 | RezeroUnit = 0x01, 6 | RequestSense = 0x03, 7 | FormatUnit = 0x04, 8 | ReassignBlocks = 0x07, 9 | /// obsolete 10 | Read6 = 0x08, 11 | /// obsolete 12 | Write6 = 0x0A, 13 | /// obsolete 14 | Seek = 0x0B, 15 | Inquiry = 0x12, 16 | ModeSelect6 = 0x15, 17 | /// obsolete 18 | Reserve6 = 0x16, 19 | /// obsolete 20 | Release6 = 0x17, 21 | ModeSense6 = 0x1A, 22 | StartStopUnit = 0x1B, 23 | RecvDiagnosticRes = 0x1C, 24 | SendDiagnostic = 0x1D, 25 | ReadCapacity10 = 0x25, 26 | Read10 = 0x28, 27 | Write10 = 0x2A, 28 | /// obsolete 29 | SeekExt = 0x2B, 30 | WriteAndVerify10 = 0x2E, 31 | Verify10 = 0x2F, 32 | SyncCache10 = 0x35, 33 | ReadDefectData10 = 0x37, 34 | WriteBuf10 = 0x3B, 35 | ReadBuf10 = 0x3C, 36 | /// obsolete 37 | ReadLong10 = 0x3E, 38 | WriteLong10 = 0x3F, 39 | /// obsolete 40 | ChangeDef = 0x40, 41 | WriteSame10 = 0x41, 42 | Unmap = 0x42, 43 | Sanitize = 0x48, 44 | LogSelect = 0x4C, 45 | LogSense = 0x4D, 46 | ModeSelect10 = 0x55, 47 | /// obsolete 48 | Reserve10 = 0x56, 49 | /// obsolete 50 | Release10 = 0x57, 51 | ModeSense10 = 0x5A, 52 | PersistentResvIn = 0x5E, 53 | PersistentResvOut = 0x5F, 54 | ServiceAction7F = 0x7F, 55 | Read16 = 0x88, 56 | Write16 = 0x8A, 57 | WriteAndVerify16 = 0x8E, 58 | Verify16 = 0x8F, 59 | SyncCache16 = 0x91, 60 | WriteSame16 = 0x93, 61 | WriteStream16 = 0x9A, 62 | ReadBuf16 = 0x9B, 63 | WriteAtomic16 = 0x9C, 64 | ServiceAction9E = 0x9E, 65 | ServiceAction9F, 66 | ReportLuns = 0xA0, 67 | SecurityProtoIn = 0xA2, 68 | ServiceActionA3 = 0xA3, 69 | ServiceActionA4 = 0xA4, 70 | Read12 = 0xA8, 71 | Write12 = 0xAA, 72 | WriteAndVerify12 = 0xAE, 73 | Verify12 = 0xAF, 74 | SecurityProtoOut = 0xB5, 75 | ReadDefectData12 = 0xB7, 76 | } 77 | 78 | #[repr(u8)] 79 | pub enum ServiceAction7F { 80 | Read32 = 0x09, 81 | Verify32 = 0x0A, 82 | Write32 = 0x0B, 83 | WriteAndVerify32 = 0x0C, 84 | WriteSame32 = 0x0D, 85 | WriteAtomic32 = 0x18, 86 | } 87 | 88 | #[repr(u8)] 89 | pub enum ServiceAction9E { 90 | ReadCapacity16 = 0x10, 91 | ReadLong16 = 0x11, 92 | GetLbaStatus = 0x12, 93 | StreamControl = 0x14, 94 | BackgroundControl = 0x15, 95 | GetStreamStatus = 0x16, 96 | } 97 | #[repr(u8)] 98 | pub enum ServiceAction9F { 99 | WriteLong16 = 0x11, 100 | } 101 | #[repr(u8)] 102 | pub enum ServiceActionA3 { 103 | ReportIdentInfo = 0x05, 104 | ReportSuppOpcodes = 0x0C, 105 | ReportSuppTaskManFuncs = 0x0D, 106 | ReportTimestamp = 0x0F, 107 | } 108 | #[repr(u8)] 109 | pub enum ServiceActionA4 { 110 | SetIdentInfo = 0x06, 111 | SetTimestamp = 0x0F, 112 | } 113 | -------------------------------------------------------------------------------- /net/e1000d/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Read, Write}; 2 | use std::os::unix::io::AsRawFd; 3 | 4 | use driver_network::NetworkScheme; 5 | use event::{user_data, EventQueue}; 6 | use pcid_interface::PciFunctionHandle; 7 | 8 | pub mod device; 9 | 10 | fn main() { 11 | let mut pcid_handle = PciFunctionHandle::connect_default(); 12 | let pci_config = pcid_handle.config(); 13 | 14 | let mut name = pci_config.func.name(); 15 | name.push_str("_e1000"); 16 | 17 | common::setup_logging( 18 | "net", 19 | "pci", 20 | &name, 21 | common::output_level(), 22 | common::file_level(), 23 | ); 24 | 25 | let irq = pci_config 26 | .func 27 | .legacy_interrupt_line 28 | .expect("e1000d: no legacy interrupts supported"); 29 | 30 | log::info!("E1000 {}", pci_config.func.display()); 31 | 32 | redox_daemon::Daemon::new(move |daemon| { 33 | let mut irq_file = irq.irq_handle("e1000d"); 34 | 35 | let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; 36 | 37 | let mut scheme = NetworkScheme::new( 38 | move || unsafe { 39 | device::Intel8254x::new(address).expect("e1000d: failed to allocate device") 40 | }, 41 | daemon, 42 | format!("network.{name}"), 43 | ); 44 | 45 | user_data! { 46 | enum Source { 47 | Irq, 48 | Scheme, 49 | } 50 | } 51 | 52 | let event_queue = 53 | EventQueue::::new().expect("e1000d: failed to create event queue"); 54 | 55 | event_queue 56 | .subscribe( 57 | irq_file.as_raw_fd() as usize, 58 | Source::Irq, 59 | event::EventFlags::READ, 60 | ) 61 | .expect("e1000d: failed to subscribe to IRQ fd"); 62 | event_queue 63 | .subscribe( 64 | scheme.event_handle().raw(), 65 | Source::Scheme, 66 | event::EventFlags::READ, 67 | ) 68 | .expect("e1000d: failed to subscribe to scheme fd"); 69 | 70 | libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); 71 | 72 | scheme.tick().unwrap(); 73 | 74 | for event in event_queue.map(|e| e.expect("e1000d: failed to get event")) { 75 | match event.user_data { 76 | Source::Irq => { 77 | let mut irq = [0; 8]; 78 | irq_file.read(&mut irq).unwrap(); 79 | if unsafe { scheme.adapter().irq() } { 80 | irq_file.write(&mut irq).unwrap(); 81 | 82 | scheme.tick().expect("e1000d: failed to handle IRQ") 83 | } 84 | } 85 | Source::Scheme => scheme.tick().expect("e1000d: failed to handle scheme op"), 86 | } 87 | } 88 | unreachable!() 89 | }) 90 | .expect("e1000d: failed to create daemon"); 91 | } 92 | -------------------------------------------------------------------------------- /graphics/graphics-ipc/src/v1.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::os::unix::io::AsRawFd; 3 | use std::{io, mem, ptr, slice}; 4 | 5 | use libredox::flag; 6 | 7 | pub use crate::common::Damage; 8 | pub use crate::common::DisplayMap; 9 | 10 | /// A graphics handle using the v1 graphics API. 11 | /// 12 | /// The v1 graphics API only allows a single framebuffer for each VT, requires each display to be 13 | /// handled separately and doesn't support page flipping. 14 | /// 15 | /// This API is stable. No breaking changes are allowed to be made without a version bump. 16 | pub struct V1GraphicsHandle { 17 | file: File, 18 | } 19 | 20 | impl V1GraphicsHandle { 21 | pub fn from_file(file: File) -> io::Result { 22 | Ok(V1GraphicsHandle { file }) 23 | } 24 | 25 | pub fn map_display(&self) -> io::Result { 26 | let mut buf: [u8; 4096] = [0; 4096]; 27 | let count = 28 | libredox::call::fpath(self.file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { 29 | panic!("Could not read display path with fpath(): {e}"); 30 | }); 31 | 32 | let url = 33 | String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); 34 | let path = url.split(':').nth(1).expect("Could not get path from url"); 35 | 36 | let mut path_parts = path.split('/').skip(1); 37 | let width = path_parts 38 | .next() 39 | .unwrap_or("") 40 | .parse::() 41 | .unwrap_or(0); 42 | let height = path_parts 43 | .next() 44 | .unwrap_or("") 45 | .parse::() 46 | .unwrap_or(0); 47 | 48 | let display_ptr = unsafe { 49 | libredox::call::mmap(libredox::call::MmapArgs { 50 | fd: self.file.as_raw_fd() as usize, 51 | offset: 0, 52 | length: (width * height * 4), 53 | prot: flag::PROT_READ | flag::PROT_WRITE, 54 | flags: flag::MAP_SHARED, 55 | addr: core::ptr::null_mut(), 56 | })? 57 | }; 58 | let offscreen = ptr::slice_from_raw_parts_mut(display_ptr as *mut u32, width * height); 59 | 60 | Ok(unsafe { DisplayMap::new(offscreen, width, height) }) 61 | } 62 | 63 | pub fn sync_full_screen(&self) -> io::Result<()> { 64 | libredox::call::fsync(self.file.as_raw_fd() as usize)?; 65 | Ok(()) 66 | } 67 | 68 | pub fn sync_rect(&self, sync_rect: Damage) -> io::Result<()> { 69 | libredox::call::write(self.file.as_raw_fd() as usize, unsafe { 70 | slice::from_raw_parts( 71 | ptr::addr_of!(sync_rect).cast::(), 72 | mem::size_of::(), 73 | ) 74 | })?; 75 | Ok(()) 76 | } 77 | } 78 | 79 | #[derive(Debug, Copy, Clone)] 80 | #[repr(C, packed)] 81 | pub struct CursorDamage { 82 | pub header: u32, 83 | pub x: i32, 84 | pub y: i32, 85 | pub hot_x: i32, 86 | pub hot_y: i32, 87 | pub width: i32, 88 | pub height: i32, 89 | pub cursor_img_bytes: [u32; 4096], 90 | } 91 | -------------------------------------------------------------------------------- /input/usbhidd/src/reqs.rs: -------------------------------------------------------------------------------- 1 | use std::slice; 2 | 3 | use rehid::report_desc::ReportTy; 4 | use xhcid_interface::{ 5 | DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, XhciClientHandleError, 6 | }; 7 | 8 | const GET_REPORT_REQ: u8 = 0x1; 9 | const SET_REPORT_REQ: u8 = 0x9; 10 | const GET_IDLE_REQ: u8 = 0x2; 11 | const SET_IDLE_REQ: u8 = 0xA; 12 | const GET_PROTOCOL_REQ: u8 = 0x3; 13 | const SET_PROTOCOL_REQ: u8 = 0xB; 14 | 15 | fn concat(hi: u8, lo: u8) -> u16 { 16 | (u16::from(hi) << 8) | u16::from(lo) 17 | } 18 | 19 | pub fn get_report( 20 | handle: &XhciClientHandle, 21 | report_ty: ReportTy, 22 | report_id: u8, 23 | if_num: u16, 24 | buffer: &mut [u8], 25 | ) -> Result<(), XhciClientHandleError> { 26 | handle.device_request( 27 | PortReqTy::Class, 28 | PortReqRecipient::Interface, 29 | GET_REPORT_REQ, 30 | concat(report_ty as u8, report_id), 31 | if_num, 32 | DeviceReqData::In(buffer), 33 | ) 34 | } 35 | pub fn set_report( 36 | handle: &XhciClientHandle, 37 | report_ty: ReportTy, 38 | report_id: u8, 39 | if_num: u16, 40 | buffer: &[u8], 41 | ) -> Result<(), XhciClientHandleError> { 42 | handle.device_request( 43 | PortReqTy::Class, 44 | PortReqRecipient::Interface, 45 | SET_REPORT_REQ, 46 | concat(report_id, report_ty as u8), 47 | if_num, 48 | DeviceReqData::Out(buffer), 49 | ) 50 | } 51 | pub fn get_idle( 52 | handle: &XhciClientHandle, 53 | report_id: u8, 54 | if_num: u16, 55 | ) -> Result { 56 | let mut idle_rate = 0; 57 | let buffer = slice::from_mut(&mut idle_rate); 58 | handle.device_request( 59 | PortReqTy::Class, 60 | PortReqRecipient::Interface, 61 | GET_IDLE_REQ, 62 | u16::from(report_id), 63 | if_num, 64 | DeviceReqData::In(buffer), 65 | )?; 66 | Ok(idle_rate) 67 | } 68 | pub fn set_idle( 69 | handle: &XhciClientHandle, 70 | duration: u8, 71 | report_id: u8, 72 | if_num: u16, 73 | ) -> Result<(), XhciClientHandleError> { 74 | handle.device_request( 75 | PortReqTy::Class, 76 | PortReqRecipient::Interface, 77 | SET_IDLE_REQ, 78 | concat(duration, report_id), 79 | if_num, 80 | DeviceReqData::NoData, 81 | ) 82 | } 83 | pub fn get_protocol(handle: &XhciClientHandle, if_num: u16) -> Result { 84 | let mut protocol = 0; 85 | let buffer = slice::from_mut(&mut protocol); 86 | handle.device_request( 87 | PortReqTy::Class, 88 | PortReqRecipient::Interface, 89 | GET_PROTOCOL_REQ, 90 | 0, 91 | if_num, 92 | DeviceReqData::In(buffer), 93 | )?; 94 | Ok(protocol) 95 | } 96 | pub fn set_protocol( 97 | handle: &XhciClientHandle, 98 | protocol: u8, 99 | if_num: u16, 100 | ) -> Result<(), XhciClientHandleError> { 101 | handle.device_request( 102 | PortReqTy::Class, 103 | PortReqRecipient::Interface, 104 | SET_PROTOCOL_REQ, 105 | u16::from(protocol), 106 | if_num, 107 | DeviceReqData::NoData, 108 | ) 109 | } 110 | -------------------------------------------------------------------------------- /pcid/src/cfg_access/fallback.rs: -------------------------------------------------------------------------------- 1 | use std::cell::Cell; 2 | use std::convert::TryFrom; 3 | use std::sync::Mutex; 4 | 5 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 6 | use common::io::{Io as _, Pio}; 7 | 8 | use log::info; 9 | use pci_types::{ConfigRegionAccess, PciAddress}; 10 | 11 | pub(crate) struct Pci { 12 | lock: Mutex<()>, 13 | } 14 | 15 | impl Pci { 16 | pub(crate) fn new() -> Self { 17 | Self { 18 | lock: Mutex::new(()), 19 | } 20 | } 21 | 22 | fn set_iopl() { 23 | // The IO privilege level is per-thread, so we need to do the initialization on every thread. 24 | thread_local! { 25 | static IOPL_ONCE: Cell = Cell::new(false); 26 | } 27 | 28 | IOPL_ONCE.with(|iopl_once| { 29 | if !iopl_once.replace(true) { 30 | // make sure that pcid is not granted io port permission unless pcie memory-mapped 31 | // configuration space is not available. 32 | info!( 33 | "PCI: couldn't find or access PCIe extended configuration, \ 34 | and thus falling back to PCI 3.0 io ports" 35 | ); 36 | common::acquire_port_io_rights().expect("pcid: failed to get IO port rights"); 37 | } 38 | }); 39 | } 40 | 41 | fn address(address: PciAddress, offset: u8) -> u32 { 42 | assert_eq!( 43 | address.segment(), 44 | 0, 45 | "usage of multiple segments requires PCIe extended configuration" 46 | ); 47 | 48 | assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); 49 | 50 | 0x80000000 51 | | (u32::from(address.bus()) << 16) 52 | | (u32::from(address.device()) << 11) 53 | | (u32::from(address.function()) << 8) 54 | | u32::from(offset) 55 | } 56 | } 57 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 58 | impl ConfigRegionAccess for Pci { 59 | unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { 60 | let _guard = self.lock.lock().unwrap(); 61 | 62 | Self::set_iopl(); 63 | 64 | let offset = 65 | u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); 66 | let address = Self::address(address, offset); 67 | 68 | Pio::::new(0xCF8).write(address); 69 | Pio::::new(0xCFC).read() 70 | } 71 | 72 | unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { 73 | let _guard = self.lock.lock().unwrap(); 74 | 75 | Self::set_iopl(); 76 | 77 | let offset = 78 | u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); 79 | let address = Self::address(address, offset); 80 | 81 | Pio::::new(0xCF8).write(address); 82 | Pio::::new(0xCFC).write(value); 83 | } 84 | } 85 | #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] 86 | impl ConfigRegionAccess for Pci { 87 | unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { 88 | let _guard = self.lock.lock().unwrap(); 89 | todo!("Pci::CfgAccess::read on this architecture") 90 | } 91 | 92 | unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) { 93 | let _guard = self.lock.lock().unwrap(); 94 | todo!("Pci::CfgAccess::write on this architecture") 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /audio/ihdad/src/hda/node.rs: -------------------------------------------------------------------------------- 1 | use super::common::*; 2 | use std::{fmt, mem}; 3 | 4 | #[derive(Clone)] 5 | pub struct HDANode { 6 | pub addr: WidgetAddr, 7 | 8 | // 0x4 9 | pub subnode_count: u16, 10 | pub subnode_start: u16, 11 | 12 | // 0x5 13 | pub function_group_type: u8, 14 | 15 | // 0x9 16 | pub capabilities: u32, 17 | 18 | // 0xE 19 | pub conn_list_len: u8, 20 | 21 | pub connections: Vec, 22 | 23 | pub connection_default: u8, 24 | 25 | pub is_widget: bool, 26 | 27 | pub config_default: u32, 28 | } 29 | 30 | impl HDANode { 31 | pub fn new() -> HDANode { 32 | HDANode { 33 | addr: (0, 0), 34 | subnode_count: 0, 35 | subnode_start: 0, 36 | function_group_type: 0, 37 | capabilities: 0, 38 | conn_list_len: 0, 39 | 40 | config_default: 0, 41 | is_widget: false, 42 | connections: Vec::::new(), 43 | connection_default: 0, 44 | } 45 | } 46 | 47 | pub fn widget_type(&self) -> HDAWidgetType { 48 | unsafe { mem::transmute(((self.capabilities >> 20) & 0xF) as u8) } 49 | } 50 | 51 | pub fn device_default(&self) -> Option { 52 | if self.widget_type() != HDAWidgetType::PinComplex { 53 | None 54 | } else { 55 | Some(unsafe { mem::transmute(((self.config_default >> 20) & 0xF) as u8) }) 56 | } 57 | } 58 | 59 | pub fn configuration_default(&self) -> ConfigurationDefault { 60 | ConfigurationDefault::from_u32(self.config_default) 61 | } 62 | 63 | pub fn addr(&self) -> WidgetAddr { 64 | self.addr 65 | } 66 | } 67 | 68 | impl fmt::Display for HDANode { 69 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 70 | if self.addr == (0, 0) { 71 | write!( 72 | f, 73 | "Addr: {:02X}:{:02X}, Root Node.", 74 | self.addr.0, self.addr.1 75 | ) 76 | } else if self.is_widget { 77 | match self.widget_type() { 78 | HDAWidgetType::PinComplex => write!( 79 | f, 80 | "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {}/{}: {:X?}.", 81 | self.addr.0, 82 | self.addr.1, 83 | self.widget_type(), 84 | self.device_default().unwrap(), 85 | self.connection_default, 86 | self.conn_list_len, 87 | self.connections 88 | ), 89 | _ => write!( 90 | f, 91 | "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {}/{}: {:X?}.", 92 | self.addr.0, 93 | self.addr.1, 94 | self.widget_type(), 95 | self.connection_default, 96 | self.conn_list_len, 97 | self.connections 98 | ), 99 | } 100 | } else { 101 | write!( 102 | f, 103 | "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", 104 | self.addr.0, self.addr.1, self.function_group_type, self.subnode_count 105 | ) 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /input/ps2d/src/vm.rs: -------------------------------------------------------------------------------- 1 | // This code is informed by the QEMU implementation found here: 2 | // https://github.com/qemu/qemu/blob/master/hw/input/vmmouse.c 3 | // 4 | // As well as the Linux implementation here: 5 | // http://elixir.free-electrons.com/linux/v4.1/source/drivers/input/mouse/vmmouse.c 6 | 7 | use core::arch::asm; 8 | 9 | use log::{error, info, trace}; 10 | 11 | const MAGIC: u32 = 0x564D5868; 12 | const PORT: u16 = 0x5658; 13 | 14 | pub const GETVERSION: u32 = 10; 15 | pub const ABSPOINTER_DATA: u32 = 39; 16 | pub const ABSPOINTER_STATUS: u32 = 40; 17 | pub const ABSPOINTER_COMMAND: u32 = 41; 18 | 19 | pub const CMD_ENABLE: u32 = 0x45414552; 20 | pub const CMD_DISABLE: u32 = 0x000000f5; 21 | pub const CMD_REQUEST_ABSOLUTE: u32 = 0x53424152; 22 | pub const CMD_REQUEST_RELATIVE: u32 = 0x4c455252; 23 | 24 | const VERSION: u32 = 0x3442554a; 25 | 26 | pub const RELATIVE_PACKET: u32 = 0x00010000; 27 | 28 | pub const LEFT_BUTTON: u32 = 0x20; 29 | pub const RIGHT_BUTTON: u32 = 0x10; 30 | pub const MIDDLE_BUTTON: u32 = 0x08; 31 | 32 | pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { 33 | let a: u32; 34 | let b: u32; 35 | let c: u32; 36 | let d: u32; 37 | 38 | // ebx can't be used as input or output constraint in rust as LLVM reserves it. 39 | // Use xchg to pass it through r9 instead while restoring the original value in 40 | // rbx when leaving the inline asm block. si and di are clobbered too. 41 | #[cfg(not(target_arch = "x86"))] 42 | asm!( 43 | "xchg r9, rbx; in eax, dx; xchg r9, rbx", 44 | inout("eax") MAGIC => a, 45 | inout("r9") arg => b, 46 | inout("ecx") cmd => c, 47 | inout("edx") PORT as u32 => d, 48 | out("rsi") _, 49 | out("rdi") _, 50 | ); 51 | 52 | // On x86 we don't have a spare register, so push ebx to the stack instead. 53 | #[cfg(target_arch = "x86")] 54 | asm!( 55 | "push ebx; mov ebx, edi; in eax, dx; mov edi, ebx; pop ebx", 56 | inout("eax") MAGIC => a, 57 | inout("edi") arg => b, 58 | inout("ecx") cmd => c, 59 | inout("edx") PORT as u32 => d, 60 | ); 61 | 62 | (a, b, c, d) 63 | } 64 | 65 | pub fn enable(relative: bool) -> bool { 66 | trace!("ps2d: Enable vmmouse"); 67 | 68 | unsafe { 69 | let (eax, ebx, _, _) = cmd(GETVERSION, 0); 70 | if ebx != MAGIC || eax == 0xFFFFFFFF { 71 | info!("ps2d: No vmmouse support"); 72 | return false; 73 | } 74 | 75 | let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); 76 | 77 | let (status, _, _, _) = cmd(ABSPOINTER_STATUS, 0); 78 | if (status & 0x0000ffff) == 0 { 79 | info!("ps2d: No vmmouse"); 80 | return false; 81 | } 82 | 83 | let (version, _, _, _) = cmd(ABSPOINTER_DATA, 1); 84 | if version != VERSION { 85 | error!( 86 | "ps2d: Invalid vmmouse version: {} instead of {}", 87 | version, VERSION 88 | ); 89 | let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE); 90 | return false; 91 | } 92 | 93 | if relative { 94 | cmd(ABSPOINTER_COMMAND, CMD_REQUEST_RELATIVE); 95 | } else { 96 | cmd(ABSPOINTER_COMMAND, CMD_REQUEST_ABSOLUTE); 97 | } 98 | } 99 | 100 | return true; 101 | } 102 | -------------------------------------------------------------------------------- /storage/virtio-blkd/src/scheme.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use common::dma::Dma; 4 | use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; 5 | use virtio_core::transport::Queue; 6 | 7 | use crate::BlockDeviceConfig; 8 | use crate::BlockRequestTy; 9 | use crate::BlockVirtRequest; 10 | 11 | trait BlkExtension { 12 | async fn read(&self, block: u64, target: &mut [u8]) -> usize; 13 | async fn write(&self, block: u64, target: &[u8]) -> usize; 14 | } 15 | 16 | impl BlkExtension for Queue<'_> { 17 | async fn read(&self, block: u64, target: &mut [u8]) -> usize { 18 | let req = Dma::new(BlockVirtRequest { 19 | ty: BlockRequestTy::In, 20 | reserved: 0, 21 | sector: block, 22 | }) 23 | .unwrap(); 24 | 25 | let result = unsafe { 26 | Dma::<[u8]>::zeroed_slice(target.len()) 27 | .unwrap() 28 | .assume_init() 29 | }; 30 | let status = Dma::new(u8::MAX).unwrap(); 31 | 32 | let chain = ChainBuilder::new() 33 | .chain(Buffer::new(&req)) 34 | .chain(Buffer::new_unsized(&result).flags(DescriptorFlags::WRITE_ONLY)) 35 | .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) 36 | .build(); 37 | 38 | // XXX: Subtract 1 because the of status byte. 39 | let written = self.send(chain).await as usize - 1; 40 | assert_eq!(*status, 0); 41 | 42 | target[..written].copy_from_slice(&result); 43 | written 44 | } 45 | 46 | async fn write(&self, block: u64, target: &[u8]) -> usize { 47 | let req = Dma::new(BlockVirtRequest { 48 | ty: BlockRequestTy::Out, 49 | reserved: 0, 50 | sector: block, 51 | }) 52 | .unwrap(); 53 | 54 | let mut result = unsafe { 55 | Dma::<[u8]>::zeroed_slice(target.len()) 56 | .unwrap() 57 | .assume_init() 58 | }; 59 | result.copy_from_slice(target.as_ref()); 60 | 61 | let status = Dma::new(u8::MAX).unwrap(); 62 | 63 | let chain = ChainBuilder::new() 64 | .chain(Buffer::new(&req)) 65 | .chain(Buffer::new_sized(&result, target.len())) 66 | .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) 67 | .build(); 68 | 69 | self.send(chain).await as usize; 70 | assert_eq!(*status, 0); 71 | 72 | target.len() 73 | } 74 | } 75 | 76 | pub(crate) struct VirtioDisk<'a> { 77 | queue: Arc>, 78 | cfg: BlockDeviceConfig, 79 | } 80 | 81 | impl<'a> VirtioDisk<'a> { 82 | pub(crate) fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { 83 | Self { queue, cfg } 84 | } 85 | } 86 | 87 | impl driver_block::Disk for VirtioDisk<'_> { 88 | fn block_size(&self) -> u32 { 89 | self.cfg.block_size() 90 | } 91 | 92 | fn size(&self) -> u64 { 93 | self.cfg.capacity() * u64::from(self.cfg.block_size()) 94 | } 95 | 96 | async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { 97 | Ok(self.queue.read(block, buffer).await) 98 | } 99 | 100 | async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { 101 | Ok(self.queue.write(block, buffer).await) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /graphics/bgad/src/scheme.rs: -------------------------------------------------------------------------------- 1 | use inputd::ProducerHandle; 2 | use redox_scheme::scheme::SchemeSync; 3 | use redox_scheme::{CallerCtx, OpenResult}; 4 | use std::str; 5 | use syscall::data::Stat; 6 | use syscall::schemev2::NewFdFlags; 7 | use syscall::{Error, Result, EACCES, EINVAL, MODE_CHR}; 8 | 9 | use crate::bga::Bga; 10 | 11 | pub struct BgaScheme { 12 | pub bga: Bga, 13 | pub display: Option, 14 | } 15 | 16 | impl BgaScheme { 17 | pub fn update_size(&mut self) { 18 | if let Some(ref mut display) = self.display { 19 | let _ = display.write_event( 20 | orbclient::ResizeEvent { 21 | width: self.bga.width() as u32, 22 | height: self.bga.height() as u32, 23 | } 24 | .to_event(), 25 | ); 26 | } 27 | } 28 | } 29 | 30 | impl SchemeSync for BgaScheme { 31 | fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result { 32 | if ctx.uid == 0 { 33 | Ok(OpenResult::ThisScheme { 34 | number: 0, 35 | flags: NewFdFlags::empty(), 36 | }) 37 | } else { 38 | Err(Error::new(EACCES)) 39 | } 40 | } 41 | 42 | fn read( 43 | &mut self, 44 | _id: usize, 45 | buf: &mut [u8], 46 | _offset: u64, 47 | _fcntl_flags: u32, 48 | _ctx: &CallerCtx, 49 | ) -> Result { 50 | let mut i = 0; 51 | let data = format!("{},{}\n", self.bga.width(), self.bga.height()).into_bytes(); 52 | while i < buf.len() && i < data.len() { 53 | buf[i] = data[i]; 54 | i += 1; 55 | } 56 | Ok(i) 57 | } 58 | 59 | fn write( 60 | &mut self, 61 | _id: usize, 62 | buf: &[u8], 63 | _offset: u64, 64 | _fcntl_flags: u32, 65 | _ctx: &CallerCtx, 66 | ) -> Result { 67 | let string = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; 68 | let string = string.trim(); 69 | 70 | let mut parts = string.split(','); 71 | 72 | let width = if let Some(part) = parts.next() { 73 | part.parse::().or(Err(Error::new(EINVAL)))? 74 | } else { 75 | self.bga.width() 76 | }; 77 | 78 | let height = if let Some(part) = parts.next() { 79 | part.parse::().or(Err(Error::new(EINVAL)))? 80 | } else { 81 | self.bga.height() 82 | }; 83 | 84 | self.bga.set_size(width, height); 85 | 86 | self.update_size(); 87 | 88 | Ok(buf.len()) 89 | } 90 | 91 | fn fpath(&mut self, _file: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { 92 | let mut i = 0; 93 | let scheme_path = b"bga"; 94 | while i < buf.len() && i < scheme_path.len() { 95 | buf[i] = scheme_path[i]; 96 | i += 1; 97 | } 98 | Ok(i) 99 | } 100 | 101 | fn fstat(&mut self, _id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { 102 | *stat = Stat { 103 | st_mode: MODE_CHR | 0o666, 104 | ..Default::default() 105 | }; 106 | 107 | Ok(()) 108 | } 109 | 110 | fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result { 111 | Ok(0) 112 | } 113 | } 114 | 115 | impl BgaScheme { 116 | pub fn on_close(&mut self, _id: usize) {} 117 | } 118 | -------------------------------------------------------------------------------- /pcid-spawner/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::process::Command; 3 | 4 | use anyhow::{anyhow, Context, Result}; 5 | 6 | use pcid_interface::config::Config; 7 | use pcid_interface::PciFunctionHandle; 8 | 9 | fn main() -> Result<()> { 10 | let mut args = pico_args::Arguments::from_env(); 11 | let config_path = args 12 | .free_from_str::() 13 | .expect("failed to parse --config argument"); 14 | 15 | common::setup_logging( 16 | "bus", 17 | "pci", 18 | "pci-spawner.log", 19 | common::output_level(), 20 | common::file_level(), 21 | ); 22 | 23 | let config_data = if fs::metadata(&config_path)?.is_file() { 24 | fs::read_to_string(&config_path)? 25 | } else { 26 | let mut config_data = String::new(); 27 | for path in fs::read_dir(&config_path)? { 28 | if let Ok(tmp) = fs::read_to_string(path.unwrap().path()) { 29 | config_data.push_str(&tmp); 30 | } 31 | } 32 | config_data 33 | }; 34 | let config: Config = toml::from_str(&config_data)?; 35 | 36 | for entry in fs::read_dir("/scheme/pci")? { 37 | let entry = entry.context("failed to get entry")?; 38 | let device_path = entry.path(); 39 | log::trace!("ENTRY: {}", device_path.to_string_lossy()); 40 | 41 | let mut handle = match PciFunctionHandle::connect_by_path(&device_path) { 42 | Ok(handle) => handle, 43 | Err(err) => { 44 | // Either the device is gone or it is already in-use by a driver. 45 | log::debug!( 46 | "pcid-spawner: {} already in use: {err}", 47 | device_path.display(), 48 | ); 49 | continue; 50 | } 51 | }; 52 | 53 | let full_device_id = handle.config().func.full_device_id; 54 | 55 | log::debug!( 56 | "pcid-spawner enumerated: PCI {} {}", 57 | handle.config().func.addr, 58 | full_device_id.display() 59 | ); 60 | 61 | let Some(driver) = config 62 | .drivers 63 | .iter() 64 | .find(|driver| driver.match_function(&full_device_id)) 65 | else { 66 | log::debug!("no driver for {}, continuing", handle.config().func.addr); 67 | continue; 68 | }; 69 | 70 | let mut args = driver.command.iter(); 71 | 72 | let program = args 73 | .next() 74 | .ok_or_else(|| anyhow!("driver configuration entry did not have any command!"))?; 75 | let program = if program.starts_with('/') { 76 | program.to_owned() 77 | } else { 78 | "/usr/lib/drivers/".to_owned() + program 79 | }; 80 | 81 | let mut command = Command::new(program); 82 | command.args(args); 83 | 84 | log::info!("pcid-spawner: spawn {:?}", command); 85 | 86 | handle.enable_device(); 87 | 88 | let channel_fd = handle.into_inner_fd(); 89 | command.env("PCID_CLIENT_CHANNEL", channel_fd.to_string()); 90 | 91 | match command.status() { 92 | Ok(status) if !status.success() => { 93 | log::error!("pcid-spawner: driver {command:?} failed with {status}"); 94 | } 95 | Ok(_) => {} 96 | Err(err) => log::error!("pcid-spawner: failed to execute {command:?}: {err}"), 97 | } 98 | syscall::close(channel_fd as usize).unwrap(); 99 | } 100 | 101 | Ok(()) 102 | } 103 | -------------------------------------------------------------------------------- /acpid/src/acpi/dmar/drhd.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | use common::io::Mmio; 4 | 5 | // TODO: Only wrap with Mmio where there are hardware-registers. (Some of these structs seem to be 6 | // ring buffer entries, which are not to be treated the same way). 7 | 8 | pub struct DrhdPage { 9 | virt: *mut Drhd, 10 | } 11 | impl DrhdPage { 12 | pub fn map(base_phys: usize) -> syscall::Result { 13 | assert_eq!( 14 | base_phys % crate::acpi::PAGE_SIZE, 15 | 0, 16 | "DRHD registers must be page-aligned" 17 | ); 18 | 19 | // TODO: Uncachable? Can reads have side-effects? 20 | let virt = unsafe { 21 | common::physmap( 22 | base_phys, 23 | crate::acpi::PAGE_SIZE, 24 | common::Prot::RO, 25 | common::MemoryType::default(), 26 | )? 27 | } as *mut Drhd; 28 | 29 | Ok(Self { virt }) 30 | } 31 | } 32 | impl Deref for DrhdPage { 33 | type Target = Drhd; 34 | 35 | fn deref(&self) -> &Self::Target { 36 | unsafe { &*self.virt } 37 | } 38 | } 39 | impl DerefMut for DrhdPage { 40 | fn deref_mut(&mut self) -> &mut Self::Target { 41 | unsafe { &mut *self.virt } 42 | } 43 | } 44 | impl Drop for DrhdPage { 45 | fn drop(&mut self) { 46 | unsafe { 47 | let _ = libredox::call::munmap(self.virt.cast(), crate::acpi::PAGE_SIZE); 48 | } 49 | } 50 | } 51 | 52 | #[repr(C, packed)] 53 | pub struct DrhdFault { 54 | pub sts: Mmio, 55 | pub ctrl: Mmio, 56 | pub data: Mmio, 57 | pub addr: [Mmio; 2], 58 | _rsv: [Mmio; 2], 59 | pub log: Mmio, 60 | } 61 | 62 | #[repr(C, packed)] 63 | pub struct DrhdProtectedMemory { 64 | pub en: Mmio, 65 | pub low_base: Mmio, 66 | pub low_limit: Mmio, 67 | pub high_base: Mmio, 68 | pub high_limit: Mmio, 69 | } 70 | 71 | #[repr(C, packed)] 72 | pub struct DrhdInvalidation { 73 | pub queue_head: Mmio, 74 | pub queue_tail: Mmio, 75 | pub queue_addr: Mmio, 76 | _rsv: Mmio, 77 | pub cmpl_sts: Mmio, 78 | pub cmpl_ctrl: Mmio, 79 | pub cmpl_data: Mmio, 80 | pub cmpl_addr: [Mmio; 2], 81 | } 82 | 83 | #[repr(C, packed)] 84 | pub struct DrhdPageRequest { 85 | pub queue_head: Mmio, 86 | pub queue_tail: Mmio, 87 | pub queue_addr: Mmio, 88 | _rsv: Mmio, 89 | pub sts: Mmio, 90 | pub ctrl: Mmio, 91 | pub data: Mmio, 92 | pub addr: [Mmio; 2], 93 | } 94 | 95 | #[repr(C, packed)] 96 | pub struct DrhdMtrrVariable { 97 | pub base: Mmio, 98 | pub mask: Mmio, 99 | } 100 | 101 | #[repr(C, packed)] 102 | pub struct DrhdMtrr { 103 | pub cap: Mmio, 104 | pub def_type: Mmio, 105 | pub fixed: [Mmio; 11], 106 | pub variable: [DrhdMtrrVariable; 10], 107 | } 108 | 109 | #[repr(C, packed)] 110 | pub struct Drhd { 111 | pub version: Mmio, 112 | _rsv: Mmio, 113 | pub cap: Mmio, 114 | pub ext_cap: Mmio, 115 | pub gl_cmd: Mmio, 116 | pub gl_sts: Mmio, 117 | pub root_table: Mmio, 118 | pub ctx_cmd: Mmio, 119 | _rsv1: Mmio, 120 | pub fault: DrhdFault, 121 | _rsv2: Mmio, 122 | pub pm: DrhdProtectedMemory, 123 | pub invl: DrhdInvalidation, 124 | _rsv3: Mmio, 125 | pub intr_table: Mmio, 126 | pub page_req: DrhdPageRequest, 127 | pub mtrr: DrhdMtrr, 128 | } 129 | -------------------------------------------------------------------------------- /usb/xhcid/src/xhci/port.rs: -------------------------------------------------------------------------------- 1 | use common::io::{Io, Mmio}; 2 | 3 | // RO - read-only 4 | // ROS - read-only sticky 5 | // RW - read/write 6 | // RWS - read/write sticky 7 | // RW1CS - read/write-1-to-clear sticky 8 | // RW1S - read/write-1-to-set 9 | // Sticky register values may preserve values through chip hardware reset 10 | 11 | bitflags! { 12 | pub struct PortFlags: u32 { 13 | const CCS = 1 << 0; // ROS 14 | const PED = 1 << 1; // RW1CS 15 | const RSVD_2 = 1 << 2; // RsvdZ 16 | const OCA = 1 << 3; // RO 17 | const PR = 1 << 4; // RW1S 18 | const PLS_0 = 1 << 5; // RWS 19 | const PLS_1 = 1 << 6; // RWS 20 | const PLS_2 = 1 << 7; // RWS 21 | const PLS_3 = 1 << 8; // RWS 22 | const PP = 1 << 9; // RWS 23 | const SPEED_0 = 1 << 10; // ROS 24 | const SPEED_1 = 1 << 11; // ROS 25 | const SPEED_2 = 1 << 12; // ROS 26 | const SPEED_3 = 1 << 13; // ROS 27 | const PIC_AMB = 1 << 14; // RWS 28 | const PIC_GRN = 1 << 15; // RWS 29 | const LWS = 1 << 16; // RW 30 | const CSC = 1 << 17; // RW1CS 31 | const PEC = 1 << 18; // RW1CS 32 | const WRC = 1 << 19; // RW1CS 33 | const OCC = 1 << 20; // RW1CS 34 | const PRC = 1 << 21; // RW1CS 35 | const PLC = 1 << 22; // RW1CS 36 | const CEC = 1 << 23; // RW1CS 37 | const CAS = 1 << 24; // RO 38 | const WCE = 1 << 25; // RWS 39 | const WDE = 1 << 26; // RWS 40 | const WOE = 1 << 27; // RWS 41 | const RSVD_28 = 1 << 28; // RsvdZ 42 | const RSVD_29 = 1 << 29; // RsvdZ 43 | const DR = 1 << 30; // RO 44 | const WPR = 1 << 31; // RW1S 45 | } 46 | } 47 | 48 | #[repr(C, packed)] 49 | pub struct Port { 50 | // This has write one to clear fields, do not expose it, handle writes carefully! 51 | portsc: Mmio, 52 | pub portpmsc: Mmio, 53 | pub portli: Mmio, 54 | pub porthlpmc: Mmio, 55 | } 56 | 57 | impl Port { 58 | pub fn read(&self) -> u32 { 59 | self.portsc.read() 60 | } 61 | 62 | pub fn clear_csc(&mut self) { 63 | self.portsc 64 | .write((self.flags_preserved() | PortFlags::CSC).bits()); 65 | } 66 | 67 | pub fn clear_prc(&mut self) { 68 | self.portsc 69 | .write((self.flags_preserved() | PortFlags::PRC).bits()); 70 | } 71 | 72 | pub fn set_pr(&mut self) { 73 | self.portsc 74 | .write((self.flags_preserved() | PortFlags::PR).bits()); 75 | } 76 | 77 | pub fn state(&self) -> u8 { 78 | ((self.read() & (0b1111 << 5)) >> 5) as u8 79 | } 80 | 81 | pub fn speed(&self) -> u8 { 82 | ((self.read() & (0b1111 << 10)) >> 10) as u8 83 | } 84 | 85 | pub fn flags(&self) -> PortFlags { 86 | PortFlags::from_bits_truncate(self.read()) 87 | } 88 | 89 | // Read only preserved flags 90 | pub fn flags_preserved(&self) -> PortFlags { 91 | // RO(S) and RW(S) bits should be preserved 92 | // RW1S and RW1CS bits should not 93 | let preserved = PortFlags::CCS 94 | | PortFlags::OCA 95 | | PortFlags::PLS_0 96 | | PortFlags::PLS_1 97 | | PortFlags::PLS_2 98 | | PortFlags::PLS_3 99 | | PortFlags::PP 100 | | PortFlags::SPEED_0 101 | | PortFlags::SPEED_1 102 | | PortFlags::SPEED_2 103 | | PortFlags::SPEED_3 104 | | PortFlags::PIC_AMB 105 | | PortFlags::PIC_GRN 106 | | PortFlags::WCE 107 | | PortFlags::WDE 108 | | PortFlags::WOE 109 | | PortFlags::DR; 110 | 111 | self.flags() & preserved 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /net/rtl8168d/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Read, Write}; 2 | use std::os::unix::io::AsRawFd; 3 | 4 | use driver_network::NetworkScheme; 5 | use event::{user_data, EventQueue}; 6 | use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; 7 | use pcid_interface::PciFunctionHandle; 8 | 9 | pub mod device; 10 | 11 | use std::ops::{Add, Div, Rem}; 12 | pub fn div_round_up(a: T, b: T) -> T 13 | where 14 | T: Add + Div + Rem + PartialEq + From + Copy, 15 | { 16 | if a % b != T::from(0u8) { 17 | a / b + T::from(1u8) 18 | } else { 19 | a / b 20 | } 21 | } 22 | 23 | fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { 24 | let config = pcid_handle.config(); 25 | 26 | // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order 27 | for &barnum in &[2, 1] { 28 | match config.func.bars[usize::from(barnum)] { 29 | pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { 30 | return pcid_handle.map_bar(barnum).ptr.as_ptr(); 31 | }, 32 | other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), 33 | } 34 | } 35 | panic!("rtl8168d: failed to find BAR"); 36 | } 37 | 38 | fn daemon(daemon: redox_daemon::Daemon) -> ! { 39 | let mut pcid_handle = PciFunctionHandle::connect_default(); 40 | 41 | let pci_config = pcid_handle.config(); 42 | 43 | let mut name = pci_config.func.name(); 44 | name.push_str("_rtl8168"); 45 | 46 | common::setup_logging( 47 | "net", 48 | "pci", 49 | &name, 50 | common::output_level(), 51 | common::file_level(), 52 | ); 53 | 54 | log::info!("RTL8168 {}", pci_config.func.display()); 55 | 56 | let bar = map_bar(&mut pcid_handle); 57 | 58 | let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8168d"); 59 | 60 | let mut scheme = NetworkScheme::new( 61 | move || unsafe { 62 | device::Rtl8168::new(bar as usize).expect("rtl8168d: failed to allocate device") 63 | }, 64 | daemon, 65 | format!("network.{name}"), 66 | ); 67 | 68 | user_data! { 69 | enum Source { 70 | Irq, 71 | Scheme, 72 | } 73 | } 74 | 75 | let event_queue = EventQueue::::new().expect("rtl8168d: Could not create event queue."); 76 | event_queue 77 | .subscribe( 78 | irq_file.irq_handle().as_raw_fd() as usize, 79 | Source::Irq, 80 | event::EventFlags::READ, 81 | ) 82 | .unwrap(); 83 | event_queue 84 | .subscribe( 85 | scheme.event_handle().raw(), 86 | Source::Scheme, 87 | event::EventFlags::READ, 88 | ) 89 | .unwrap(); 90 | 91 | libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); 92 | 93 | scheme.tick().unwrap(); 94 | 95 | for event in event_queue.map(|e| e.expect("rtl8168d: failed to get next event")) { 96 | match event.user_data { 97 | Source::Irq => { 98 | let mut irq = [0; 8]; 99 | irq_file.irq_handle().read(&mut irq).unwrap(); 100 | //TODO: This may be causing spurious interrupts 101 | if unsafe { scheme.adapter_mut().irq() } { 102 | irq_file.irq_handle().write(&mut irq).unwrap(); 103 | 104 | scheme.tick().unwrap(); 105 | } 106 | } 107 | Source::Scheme => { 108 | scheme.tick().unwrap(); 109 | } 110 | } 111 | } 112 | unreachable!() 113 | } 114 | 115 | fn main() { 116 | redox_daemon::Daemon::new(daemon).expect("rtl8168d: failed to create daemon"); 117 | } 118 | -------------------------------------------------------------------------------- /net/rtl8139d/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Read, Write}; 2 | use std::os::unix::io::AsRawFd; 3 | 4 | use driver_network::NetworkScheme; 5 | use event::{user_data, EventQueue}; 6 | use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; 7 | use pcid_interface::PciFunctionHandle; 8 | 9 | pub mod device; 10 | 11 | use std::ops::{Add, Div, Rem}; 12 | pub fn div_round_up(a: T, b: T) -> T 13 | where 14 | T: Add + Div + Rem + PartialEq + From + Copy, 15 | { 16 | if a % b != T::from(0u8) { 17 | a / b + T::from(1u8) 18 | } else { 19 | a / b 20 | } 21 | } 22 | 23 | fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { 24 | let config = pcid_handle.config(); 25 | 26 | // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order 27 | for &barnum in &[2, 1] { 28 | match config.func.bars[usize::from(barnum)] { 29 | pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { 30 | return pcid_handle.map_bar(barnum).ptr.as_ptr(); 31 | }, 32 | other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), 33 | } 34 | } 35 | panic!("rtl8139d: failed to find BAR"); 36 | } 37 | 38 | fn daemon(daemon: redox_daemon::Daemon) -> ! { 39 | let mut pcid_handle = PciFunctionHandle::connect_default(); 40 | 41 | let pci_config = pcid_handle.config(); 42 | 43 | let mut name = pci_config.func.name(); 44 | name.push_str("_rtl8139"); 45 | 46 | common::setup_logging( 47 | "net", 48 | "pci", 49 | &name, 50 | common::output_level(), 51 | common::file_level(), 52 | ); 53 | 54 | log::info!(" + RTL8139 {}", pci_config.func.display()); 55 | 56 | let bar = map_bar(&mut pcid_handle); 57 | 58 | let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8139d"); 59 | 60 | let mut scheme = NetworkScheme::new( 61 | move || unsafe { 62 | device::Rtl8139::new(bar as usize).expect("rtl8139d: failed to allocate device") 63 | }, 64 | daemon, 65 | format!("network.{name}"), 66 | ); 67 | 68 | user_data! { 69 | enum Source { 70 | Irq, 71 | Scheme, 72 | } 73 | } 74 | 75 | let event_queue = EventQueue::::new().expect("rtl8139d: Could not create event queue."); 76 | event_queue 77 | .subscribe( 78 | irq_file.irq_handle().as_raw_fd() as usize, 79 | Source::Irq, 80 | event::EventFlags::READ, 81 | ) 82 | .unwrap(); 83 | event_queue 84 | .subscribe( 85 | scheme.event_handle().raw(), 86 | Source::Scheme, 87 | event::EventFlags::READ, 88 | ) 89 | .unwrap(); 90 | 91 | libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); 92 | 93 | scheme.tick().unwrap(); 94 | 95 | for event in event_queue.map(|e| e.expect("rtl8139d: failed to get next event")) { 96 | match event.user_data { 97 | Source::Irq => { 98 | let mut irq = [0; 8]; 99 | irq_file.irq_handle().read(&mut irq).unwrap(); 100 | //TODO: This may be causing spurious interrupts 101 | if unsafe { scheme.adapter_mut().irq() } { 102 | irq_file.irq_handle().write(&mut irq).unwrap(); 103 | 104 | scheme.tick().unwrap(); 105 | } 106 | } 107 | Source::Scheme => { 108 | scheme.tick().unwrap(); 109 | } 110 | } 111 | } 112 | unreachable!() 113 | } 114 | 115 | fn main() { 116 | redox_daemon::Daemon::new(daemon).expect("rtl8139d: failed to create daemon"); 117 | } 118 | -------------------------------------------------------------------------------- /storage/ahcid/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction 2 | 3 | use std::io::{Read, Write}; 4 | use std::os::fd::AsRawFd; 5 | use std::usize; 6 | 7 | use common::io::Io; 8 | use driver_block::{DiskScheme, ExecutorTrait, FuturesExecutor}; 9 | use event::{EventFlags, RawEventQueue}; 10 | use pcid_interface::PciFunctionHandle; 11 | 12 | use log::{error, info}; 13 | 14 | pub mod ahci; 15 | 16 | fn main() { 17 | redox_daemon::Daemon::new(daemon).expect("ahcid: failed to daemonize"); 18 | } 19 | 20 | fn daemon(daemon: redox_daemon::Daemon) -> ! { 21 | let mut pcid_handle = PciFunctionHandle::connect_default(); 22 | let pci_config = pcid_handle.config(); 23 | 24 | let mut name = pci_config.func.name(); 25 | name.push_str("_ahci"); 26 | 27 | let irq = pci_config 28 | .func 29 | .legacy_interrupt_line 30 | .expect("ahcid: no legacy interrupts supported"); 31 | 32 | common::setup_logging( 33 | "disk", 34 | "pci", 35 | &name, 36 | common::output_level(), 37 | common::file_level(), 38 | ); 39 | 40 | info!("AHCI {}", pci_config.func.display()); 41 | 42 | let address = unsafe { pcid_handle.map_bar(5) }.ptr.as_ptr() as usize; 43 | { 44 | let (hba_mem, disks) = ahci::disks(address as usize, &name); 45 | 46 | let scheme_name = format!("disk.{}", name); 47 | let mut scheme = DiskScheme::new( 48 | Some(daemon), 49 | scheme_name, 50 | disks 51 | .into_iter() 52 | .enumerate() 53 | .map(|(i, disk)| (i as u32, disk)) 54 | .collect(), 55 | &FuturesExecutor, 56 | ); 57 | 58 | let mut irq_file = irq.irq_handle("ahcid"); 59 | let irq_fd = irq_file.as_raw_fd() as usize; 60 | 61 | let event_queue = RawEventQueue::new().expect("ahcid: failed to create event queue"); 62 | 63 | libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); 64 | 65 | event_queue 66 | .subscribe(scheme.event_handle().raw(), 1, EventFlags::READ) 67 | .expect("ahcid: failed to event scheme socket"); 68 | event_queue 69 | .subscribe(irq_fd, 1, EventFlags::READ) 70 | .expect("ahcid: failed to event irq scheme"); 71 | 72 | for event in event_queue { 73 | let event = event.unwrap(); 74 | if event.fd == scheme.event_handle().raw() { 75 | FuturesExecutor.block_on(scheme.tick()).unwrap(); 76 | } else if event.fd == irq_fd { 77 | let mut irq = [0; 8]; 78 | if irq_file 79 | .read(&mut irq) 80 | .expect("ahcid: failed to read irq file") 81 | >= irq.len() 82 | { 83 | let is = hba_mem.is.read(); 84 | if is > 0 { 85 | let pi = hba_mem.pi.read(); 86 | let pi_is = pi & is; 87 | for i in 0..hba_mem.ports.len() { 88 | if pi_is & 1 << i > 0 { 89 | let port = &mut hba_mem.ports[i]; 90 | let is = port.is.read(); 91 | port.is.write(is); 92 | } 93 | } 94 | hba_mem.is.write(is); 95 | 96 | irq_file 97 | .write(&irq) 98 | .expect("ahcid: failed to write irq file"); 99 | 100 | FuturesExecutor.block_on(scheme.tick()).unwrap(); 101 | } 102 | } 103 | } else { 104 | error!("Unknown event {}", event.fd); 105 | } 106 | } 107 | } 108 | 109 | std::process::exit(0); 110 | } 111 | -------------------------------------------------------------------------------- /net/virtio-netd/src/scheme.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use driver_network::NetworkAdapter; 4 | 5 | use common::dma::Dma; 6 | 7 | use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; 8 | use virtio_core::transport::Queue; 9 | 10 | use crate::{VirtHeader, MAX_BUFFER_LEN}; 11 | 12 | pub struct VirtioNet<'a> { 13 | mac_address: [u8; 6], 14 | 15 | /// Reciever Queue. 16 | rx: Arc>, 17 | rx_buffers: Vec>, 18 | 19 | /// Transmiter Queue. 20 | tx: Arc>, 21 | 22 | recv_head: u16, 23 | } 24 | 25 | impl<'a> VirtioNet<'a> { 26 | pub fn new(mac_address: [u8; 6], rx: Arc>, tx: Arc>) -> Self { 27 | // Populate all of the `rx_queue` with buffers to maximize performence. 28 | let mut rx_buffers = vec![]; 29 | for i in 0..(rx.descriptor_len() as usize) { 30 | rx_buffers.push(unsafe { 31 | Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN) 32 | .unwrap() 33 | .assume_init() 34 | }); 35 | 36 | let chain = ChainBuilder::new() 37 | .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) 38 | .build(); 39 | 40 | let _ = rx.send(chain); 41 | } 42 | 43 | Self { 44 | mac_address, 45 | 46 | rx, 47 | rx_buffers, 48 | tx, 49 | 50 | recv_head: 0, 51 | } 52 | } 53 | 54 | /// Returns the number of bytes read. Returns `0` if the operation would block. 55 | fn try_recv(&mut self, target: &mut [u8]) -> usize { 56 | let header_size = core::mem::size_of::(); 57 | 58 | if self.recv_head == self.rx.used.head_index() { 59 | // The read would block. 60 | return 0; 61 | } 62 | 63 | let idx = self.rx.used.head_index() as usize; 64 | let element = self.rx.used.get_element_at(idx - 1); 65 | 66 | let descriptor_idx = element.table_index.get(); 67 | let payload_size = element.written.get() as usize - header_size; 68 | 69 | // XXX: The header and packet are added as one output descriptor to the transmit queue, 70 | // and the device is notified of the new entry (see 5.1.5 Device Initialization). 71 | let buffer = &self.rx_buffers[descriptor_idx as usize]; 72 | // TODO: Check the header. 73 | let _header = unsafe { &*(buffer.as_ptr() as *const VirtHeader) }; 74 | let packet = &buffer[header_size..(header_size + payload_size)]; 75 | 76 | // Copy the packet into the buffer. 77 | target[..payload_size].copy_from_slice(&packet); 78 | 79 | self.recv_head = self.rx.used.head_index(); 80 | payload_size 81 | } 82 | } 83 | 84 | impl<'a> NetworkAdapter for VirtioNet<'a> { 85 | fn mac_address(&mut self) -> [u8; 6] { 86 | self.mac_address 87 | } 88 | 89 | fn available_for_read(&mut self) -> usize { 90 | (self.rx.used.head_index() - self.recv_head).into() 91 | } 92 | 93 | fn read_packet(&mut self, buf: &mut [u8]) -> syscall::Result> { 94 | let bytes = self.try_recv(buf); 95 | 96 | if bytes != 0 { 97 | // We read some bytes. 98 | Ok(Some(bytes)) 99 | } else { 100 | Ok(None) 101 | } 102 | } 103 | 104 | fn write_packet(&mut self, buffer: &[u8]) -> syscall::Result { 105 | let header = unsafe { Dma::::zeroed()?.assume_init() }; 106 | 107 | let mut payload = unsafe { Dma::<[u8]>::zeroed_slice(buffer.len())?.assume_init() }; 108 | payload.copy_from_slice(buffer); 109 | 110 | let chain = ChainBuilder::new() 111 | .chain(Buffer::new(&header)) 112 | .chain(Buffer::new_unsized(&payload)) 113 | .build(); 114 | 115 | futures::executor::block_on(self.tx.send(chain)); 116 | Ok(buffer.len()) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /.gitlab/issue_templates/Issue_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | - [ ] I agree that I have searched opened and closed issues to prevent duplicates. 6 | 7 | -------------------- 8 | 9 | 10 | 11 | ## Description 12 | 13 | Replace me 14 | 15 | 16 | 17 | ## Environment info 18 | 19 | 20 | 21 | - Redox OS Release: 22 | 0.0.0 Remove me 23 | 24 | 25 | - Operating system: 26 | Replace me 27 | - `uname -a`: 28 | `Replace me` 29 | - `rustc -V`: 30 | `Replace me` 31 | - `git rev-parse HEAD`: 32 | `Replace me` 33 | 34 | - Replace me: 35 | Replace me 36 | 37 | 38 | 39 | ## Steps to reproduce 40 | 41 | 1. Replace me 42 | 2. Replace me 43 | 3. ... 44 | 45 | 46 | 47 | ## Behavior 48 | 49 | 50 | 51 | - **Expected behavior**: 52 | Replace me 53 | 54 | 55 | - **Actual behavior**: 56 | Replace me 57 | 58 | 59 | ``` 60 | Replace me 61 | ``` 62 | 63 | 64 | - **Proposed solution**: 65 | Replace me 66 | 67 | 68 | 69 | 70 | 71 | ## Optional references 72 | 73 | 74 | Related to: 75 | - #0000 Remove me 76 | - Replace me 77 | - ... 78 | 79 | Blocked by: 80 | - #0000 Remove me 81 | - ... 82 | 83 | 84 | 85 | ## Optional extras 86 | 87 | Replace me 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /audio/sb16d/src/main.rs: -------------------------------------------------------------------------------- 1 | //#![deny(warnings)] 2 | 3 | use libredox::{flag, Fd}; 4 | use redox_scheme::wrappers::ReadinessBased; 5 | use redox_scheme::Socket; 6 | use std::cell::RefCell; 7 | use std::{env, usize}; 8 | 9 | use event::{user_data, EventQueue}; 10 | 11 | pub mod device; 12 | 13 | fn main() { 14 | let mut args = env::args().skip(1); 15 | 16 | let addr_str = args.next().unwrap_or("220".to_string()); 17 | let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); 18 | 19 | println!(" + sb16 at 0x{:X}\n", addr); 20 | 21 | // Daemonize 22 | redox_daemon::Daemon::new(move |daemon| { 23 | common::setup_logging( 24 | "audio", 25 | "pci", 26 | "sb16", 27 | common::output_level(), 28 | common::file_level(), 29 | ); 30 | 31 | common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); 32 | 33 | let device = RefCell::new(unsafe { 34 | device::Sb16::new(addr).expect("sb16d: failed to allocate device") 35 | }); 36 | let socket = Socket::nonblock("audiohw").expect("sb16d: failed to create socket"); 37 | let mut readiness_based = ReadinessBased::new(&socket, 16); 38 | 39 | //TODO: error on multiple IRQs? 40 | let irq_file = match device.borrow().irqs.first() { 41 | Some(irq) => Fd::open(&format!("/scheme/irq/{}", irq), flag::O_RDWR, 0) 42 | .expect("sb16d: failed to open IRQ file"), 43 | None => panic!("sb16d: no IRQs found"), 44 | }; 45 | user_data! { 46 | enum Source { 47 | Irq, 48 | Scheme, 49 | } 50 | } 51 | 52 | let event_queue = 53 | EventQueue::::new().expect("sb16d: Could not create event queue."); 54 | event_queue 55 | .subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ) 56 | .unwrap(); 57 | event_queue 58 | .subscribe( 59 | socket.inner().raw(), 60 | Source::Scheme, 61 | event::EventFlags::READ, 62 | ) 63 | .unwrap(); 64 | 65 | daemon.ready().expect("sb16d: failed to signal readiness"); 66 | 67 | libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace"); 68 | 69 | let all = [Source::Irq, Source::Scheme]; 70 | 71 | for event in all 72 | .into_iter() 73 | .chain(event_queue.map(|e| e.expect("sb16d: failed to get next event").user_data)) 74 | { 75 | match event { 76 | Source::Irq => { 77 | let mut irq = [0; 8]; 78 | irq_file.read(&mut irq).unwrap(); 79 | 80 | if !device.borrow_mut().irq() { 81 | continue; 82 | } 83 | irq_file.write(&mut irq).unwrap(); 84 | 85 | readiness_based 86 | .poll_all_requests(|| device.borrow_mut()) 87 | .expect("sb16d: failed to poll requests"); 88 | 89 | /* 90 | let next_read = device_irq.next_read(); 91 | if next_read > 0 { 92 | return Ok(Some(next_read)); 93 | } 94 | */ 95 | } 96 | Source::Scheme => { 97 | if !readiness_based 98 | .read_requests() 99 | .expect("sb16d: failed to read from socket") 100 | { 101 | break; 102 | } 103 | readiness_based.process_requests(|| device.borrow_mut()); 104 | if !readiness_based 105 | .write_responses() 106 | .expect("sb16d: failed to write to socket") 107 | { 108 | break; 109 | } 110 | } 111 | } 112 | } 113 | 114 | std::process::exit(0); 115 | }) 116 | .expect("sb16d: failed to daemonize"); 117 | } 118 | -------------------------------------------------------------------------------- /usb/xhcid/src/xhci/operational.rs: -------------------------------------------------------------------------------- 1 | use common::io::{Io, Mmio}; 2 | 3 | /// The XHCI Operational Registers 4 | /// 5 | /// These registers specify the operational state of the XHCI device, and are used to receive status 6 | /// messages and transmit commands. These registers are offset from the XHCI base address by the 7 | /// "length" field of the [CapabilityRegs] 8 | /// 9 | /// See XHCI section 5.4. Table 5-18 describes the offset of these registers in memory. 10 | #[repr(C, packed)] 11 | pub struct OperationalRegs { 12 | /// The USB Command Register (USBCMD) 13 | /// 14 | /// Describes the command to be executed by the XHCI. Writes to this register case a command 15 | /// to be executed. 16 | /// 17 | /// - Bit 0 is the Run/Stop bit (R/S). Writing a value of 1 stops the xHC from executing the schedule, 1 resumes. Latency is ~16ms at worst. (See XHCI Table 5-20) 18 | /// - Bit 1 is the Host Controller Reset Bit (HCRST). Used by software to reset the host controller (See XHCI Table 5-20) 19 | /// - Bit 2 is the Interrupter Enable Bit (INTE). Enables interrupting the host system. 20 | /// - Bit 3 is the Host System Error Enable Bit (HSEE). Enables out-of-band error signalling to the host. 21 | /// - Bits 4-6 are reserved. 22 | /// - Bit 7 is the Light Host Controller Reset Bit (LHCRST). Resets the driver without affecting the state of the ports. Affected by [CapabilityRegs] 23 | /// - Bit 8 is the Controller Save State Bit (CSS). See XHCI Table 5-20 24 | /// - Bit 9 is the Controller Restore State Bit (CRS). See XHCI Table 5-20 25 | /// - Bit 10 is the Enable Wrap Event Bit (EWE). See XHCI Table 5-20 26 | /// - Bit 11 is the Enable U3 MFINDEX Stop Bit (EU3S). See XHCI Table 5-20 27 | /// - Bit 12 is reserved. 28 | /// - Bit 13 is the CEM Enable Bit (CME). See XHCI Table 5-20 29 | /// - Bit 14 is the Extended TBC Enable Bit (ETE). See XHCI Table 5-20 30 | /// - Bit 15 is the Extended TBC TRB Status Enable Bit (TSC_En). See XHCI Table 5-20 31 | /// - Bit 16 is the VTIO Enable Bit (VTIOE). Controls the enable state of the VTIO capability. 32 | /// - Bits 17-31 are reserved. 33 | /// 34 | pub usb_cmd: Mmio, 35 | /// The USB Status Register (USBSTS) 36 | /// 37 | /// This register indicates pending interrupts and various states of the host controller. 38 | /// 39 | /// Software sets a bit to '0' in this register by writing a 1 to it. 40 | /// 41 | /// 42 | pub usb_sts: Mmio, 43 | /// The PAGESIZE Register (PAGESIZE) 44 | /// 45 | /// 46 | pub page_size: Mmio, 47 | /// Reserved bits (RsvdZ) 48 | _rsvd: [Mmio; 2], 49 | /// The Device Notification Control Register (DNCTRL) 50 | /// 51 | /// 52 | pub dn_ctrl: Mmio, 53 | /// The Command Ring Control Register Lower 32 bits (CRCR) 54 | /// 55 | /// 56 | pub crcr_low: Mmio, 57 | /// The Command Ring Control Register Upper 32 bits (CRCR) 58 | /// 59 | /// 60 | pub crcr_high: Mmio, 61 | /// Reserved bits (RsvdZ) 62 | _rsvd2: [Mmio; 4], 63 | /// Device Context Base Address Array Pointer Lower 32 bits (DCBAAP) 64 | /// 65 | /// 66 | pub dcbaap_low: Mmio, 67 | /// Device Context Base Address Array Pointer Upper 32 bits (DCBAAP) 68 | /// 69 | /// 70 | pub dcbaap_high: Mmio, 71 | /// The Configure Register (CONFIG) 72 | /// 73 | /// 74 | pub config: Mmio, 75 | // The standard has another set of reserved bits from 3C-3FFh here 76 | // The standard has 400-13FFh has a Port Register Set here (likely defined in port.rs). 77 | } 78 | 79 | // Run/stop 80 | pub const USB_CMD_RS: u32 = 1 << 0; 81 | /// Host controller reset 82 | pub const USB_CMD_HCRST: u32 = 1 << 1; 83 | // Interrupter enable 84 | pub const USB_CMD_INTE: u32 = 1 << 2; 85 | 86 | /// Host controller halted 87 | pub const USB_STS_HCH: u32 = 1 << 0; 88 | /// Host controller not ready 89 | pub const USB_STS_CNR: u32 = 1 << 11; 90 | 91 | /// The mask to get the CIE bit from the Config register. See [OperationalRegs] 92 | pub const OP_CONFIG_CIE_BIT: u32 = 1 << 9; 93 | 94 | impl OperationalRegs { 95 | pub fn cie(&self) -> bool { 96 | self.config.readf(OP_CONFIG_CIE_BIT) 97 | } 98 | pub fn set_cie(&mut self, value: bool) { 99 | self.config.writef(OP_CONFIG_CIE_BIT, value) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /storage/bcm2835-sdhcid/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::process; 2 | 3 | use driver_block::{DiskScheme, ExecutorTrait, TrivialExecutor}; 4 | use event::{EventFlags, RawEventQueue}; 5 | use fdt::Fdt; 6 | 7 | mod sd; 8 | 9 | #[cfg(target_os = "redox")] 10 | fn get_dtb() -> Vec { 11 | std::fs::read("kernel.dtb:").unwrap() 12 | } 13 | 14 | #[cfg(target_os = "linux")] 15 | fn get_dtb() -> Vec { 16 | use std::env; 17 | if let Some(arg1) = env::args().nth(1) { 18 | std::fs::read(arg1).unwrap() 19 | } else { 20 | Vec::new() 21 | } 22 | } 23 | 24 | fn main() { 25 | redox_daemon::Daemon::new(daemon).expect("mmc:failed to daemonize"); 26 | } 27 | 28 | fn daemon(daemon: redox_daemon::Daemon) -> ! { 29 | let dtb_data = get_dtb(); 30 | println!("read from OS, len = {}", dtb_data.len()); 31 | if dtb_data.len() == 0 { 32 | process::exit(0); 33 | } 34 | 35 | let fdt = Fdt::new(&dtb_data).unwrap(); 36 | println!("DTB model = {}", fdt.root().model()); 37 | let with = ["brcm,bcm2835-sdhci"]; 38 | let compat_node = fdt.find_compatible(&with).unwrap(); 39 | let reg = compat_node.reg().unwrap().next().unwrap(); 40 | let reg_size = reg.size.unwrap(); 41 | let mut reg_addr = reg.starting_address as usize; 42 | println!( 43 | "DeviceMemory start = 0x{:08x}, size = 0x{:08x}", 44 | reg_addr, reg_size 45 | ); 46 | if let Some(mut ranges) = fdt.find_node("/soc").and_then(|f| f.ranges()) { 47 | let range = ranges 48 | .find(|f| f.child_bus_address <= reg_addr && reg_addr - f.child_bus_address < f.size) 49 | .expect("Couldn't find device range in /soc/@ranges"); 50 | reg_addr = range.parent_bus_address + (reg_addr - range.child_bus_address); 51 | println!( 52 | "DeviceMemory remapped onto CPU address space: start = 0x{:08x}, size = 0x{:08x}", 53 | reg_addr, reg_size 54 | ); 55 | } 56 | 57 | let addr = unsafe { 58 | common::physmap( 59 | reg_addr, 60 | reg_size, 61 | common::Prot::RW, 62 | common::MemoryType::DeviceMemory, 63 | ) 64 | .expect("bcm2835-sdhcid: failed to map address") as usize 65 | }; 66 | println!( 67 | "ioremap 0x{:08x} to 0x{:08x} 2222", 68 | reg.starting_address as usize, addr 69 | ); 70 | let mut sdhci = sd::SdHostCtrl::new(addr); 71 | unsafe { 72 | sdhci.init(); 73 | /* 74 | let mut buf1 = [0u32; 512]; 75 | sdhci.sd_readblock(1, &mut buf1, 1); 76 | println!("readblock {:?}", buf1); 77 | buf1[0] = 0xdead_0000; 78 | buf1[1] = 0xdead_0000; 79 | buf1[2] = 0x0000_dead; 80 | buf1[3] = 0x0000_dead; 81 | sdhci.sd_writeblock(1, &buf1, 1); 82 | sdhci.sd_readblock(1, &mut buf1, 1); 83 | println!("readblock {:?}", buf1); 84 | */ 85 | /* 86 | let mut buf1 = [0u8; 512]; 87 | sdhci.read(1, &mut buf1); 88 | println!("readblock {:?}", buf1); 89 | buf1[0] = 0xde; 90 | buf1[1] = 0xad; 91 | buf1[2] = 0xde; 92 | buf1[3] = 0xad; 93 | sdhci.write(1, &buf1); 94 | sdhci.read(1, &mut buf1); 95 | println!("readblock {:?}", buf1); 96 | */ 97 | } 98 | 99 | let mut disks = Vec::new(); 100 | disks.push(sdhci); 101 | let mut scheme = DiskScheme::new( 102 | Some(daemon), 103 | "disk.mmc".to_string(), 104 | disks 105 | .into_iter() 106 | .enumerate() 107 | .map(|(i, disk)| (i as u32, disk)) 108 | .collect(), 109 | &TrivialExecutor, // TODO: real executor 110 | ); 111 | 112 | let event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); 113 | event_queue 114 | .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) 115 | .expect("mmcd: failed to event disk scheme"); 116 | 117 | libredox::call::setrens(0, 0).expect("mmcd: failed to enter null namespace"); 118 | 119 | for event in event_queue { 120 | let event = event.unwrap(); 121 | if event.fd == scheme.event_handle().raw() { 122 | TrivialExecutor.block_on(scheme.tick()).unwrap(); 123 | } else { 124 | println!("Unknown event {}", event.fd); 125 | } 126 | } 127 | process::exit(0); 128 | } 129 | -------------------------------------------------------------------------------- /net/virtio-netd/src/main.rs: -------------------------------------------------------------------------------- 1 | mod scheme; 2 | 3 | use std::fs::File; 4 | use std::io::{Read, Write}; 5 | use std::mem; 6 | 7 | use driver_network::NetworkScheme; 8 | use pcid_interface::PciFunctionHandle; 9 | 10 | use scheme::VirtioNet; 11 | 12 | pub const VIRTIO_NET_F_MAC: u32 = 5; 13 | 14 | #[derive(Debug)] 15 | #[repr(C)] 16 | pub struct VirtHeader { 17 | pub flags: u8, 18 | pub gso_type: u8, 19 | pub hdr_len: u16, 20 | pub gso_size: u16, 21 | pub csum_start: u16, 22 | pub csum_offset: u16, 23 | pub num_buffers: u16, 24 | } 25 | 26 | static_assertions::const_assert_eq!(core::mem::size_of::(), 12); 27 | 28 | const MAX_BUFFER_LEN: usize = 65535; 29 | 30 | fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box> { 31 | let mut pcid_handle = PciFunctionHandle::connect_default(); 32 | 33 | // Double check that we have the right device. 34 | // 35 | // 0x1000 - virtio-net 36 | let pci_config = pcid_handle.config(); 37 | 38 | assert_eq!(pci_config.func.full_device_id.device_id, 0x1000); 39 | log::info!("virtio-net: initiating startup sequence :^)"); 40 | 41 | let device = virtio_core::probe_device(&mut pcid_handle)?; 42 | let device_space = device.device_space; 43 | 44 | // Negotiate device features: 45 | let mac_address = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { 46 | let mac = unsafe { 47 | [ 48 | core::ptr::read_volatile(device_space.add(0)), 49 | core::ptr::read_volatile(device_space.add(1)), 50 | core::ptr::read_volatile(device_space.add(2)), 51 | core::ptr::read_volatile(device_space.add(3)), 52 | core::ptr::read_volatile(device_space.add(4)), 53 | core::ptr::read_volatile(device_space.add(5)), 54 | ] 55 | }; 56 | 57 | log::info!( 58 | "virtio-net: device MAC is {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", 59 | mac[0], 60 | mac[1], 61 | mac[2], 62 | mac[3], 63 | mac[4], 64 | mac[5] 65 | ); 66 | 67 | device.transport.ack_driver_feature(VIRTIO_NET_F_MAC); 68 | mac 69 | } else { 70 | unimplemented!() 71 | }; 72 | 73 | device.transport.finalize_features(); 74 | 75 | // Allocate the recieve and transmit queues: 76 | // 77 | // > Empty buffers are placed in one virtqueue for receiving 78 | // > packets, and outgoing packets are enqueued into another 79 | // > for transmission in that order. 80 | // 81 | // TODO(andypython): Should we use the same IRQ vector for both? 82 | let rx_queue = device 83 | .transport 84 | .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; 85 | 86 | let tx_queue = device 87 | .transport 88 | .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; 89 | 90 | device.transport.run_device(); 91 | 92 | let mut name = pci_config.func.name(); 93 | name.push_str("_virtio_net"); 94 | 95 | let device = VirtioNet::new(mac_address, rx_queue, tx_queue); 96 | let mut scheme = NetworkScheme::new( 97 | move || { 98 | //TODO: do device init in this function to prevent hangs 99 | device 100 | }, 101 | daemon, 102 | format!("network.{name}"), 103 | ); 104 | 105 | let mut event_queue = File::open("/scheme/event")?; 106 | event_queue.write(&syscall::Event { 107 | id: scheme.event_handle().raw(), 108 | flags: syscall::EVENT_READ, 109 | data: 0, 110 | })?; 111 | 112 | libredox::call::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); 113 | 114 | scheme.tick()?; 115 | 116 | loop { 117 | event_queue.read(&mut [0; mem::size_of::()])?; // Wait for event 118 | scheme.tick()?; 119 | } 120 | } 121 | 122 | fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { 123 | deamon(redox_daemon).unwrap(); 124 | unreachable!(); 125 | } 126 | 127 | pub fn main() { 128 | common::setup_logging( 129 | "net", 130 | "pci", 131 | "virtio-netd", 132 | common::output_level(), 133 | common::file_level(), 134 | ); 135 | redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); 136 | } 137 | -------------------------------------------------------------------------------- /graphics/fbcond/src/display.rs: -------------------------------------------------------------------------------- 1 | use console_draw::TextScreen; 2 | use graphics_ipc::v2::{Damage, V2GraphicsHandle}; 3 | use inputd::ConsumerHandle; 4 | use std::{io, ptr}; 5 | 6 | pub struct Display { 7 | pub input_handle: ConsumerHandle, 8 | pub map: Option, 9 | } 10 | 11 | pub struct DisplayMap { 12 | display_handle: V2GraphicsHandle, 13 | fb: usize, 14 | pub inner: graphics_ipc::v2::DisplayMap, 15 | } 16 | 17 | impl Display { 18 | pub fn open_new_vt() -> io::Result { 19 | let mut display = Self { 20 | input_handle: ConsumerHandle::new_vt()?, 21 | map: None, 22 | }; 23 | 24 | display.reopen_for_handoff(); 25 | 26 | Ok(display) 27 | } 28 | 29 | /// Re-open the display after a handoff. 30 | pub fn reopen_for_handoff(&mut self) { 31 | let display_file = self.input_handle.open_display_v2().unwrap(); 32 | let new_display_handle = V2GraphicsHandle::from_file(display_file).unwrap(); 33 | 34 | log::debug!("fbcond: Opened new display"); 35 | 36 | let (width, height) = new_display_handle.display_size(0).unwrap(); 37 | let fb = new_display_handle 38 | .create_dumb_framebuffer(width, height) 39 | .unwrap(); 40 | 41 | match new_display_handle.map_dumb_framebuffer(fb, width, height) { 42 | Ok(map) => { 43 | log::debug!( 44 | "fbcond: Mapped new display with size {}x{}", 45 | map.width(), 46 | map.height() 47 | ); 48 | 49 | self.map = Some(DisplayMap { 50 | display_handle: new_display_handle, 51 | fb, 52 | inner: map, 53 | }); 54 | } 55 | Err(err) => { 56 | log::error!("failed to map display: {}", err); 57 | } 58 | } 59 | } 60 | 61 | pub fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) { 62 | let (width, height) = match map.display_handle.display_size(0) { 63 | Ok((width, height)) => (width, height), 64 | Err(err) => { 65 | log::error!("fbcond: failed to get display size: {}", err); 66 | (map.inner.width() as u32, map.inner.height() as u32) 67 | } 68 | }; 69 | 70 | if width as usize != map.inner.width() || height as usize != map.inner.height() { 71 | match map.display_handle.create_dumb_framebuffer(width, height) { 72 | Ok(fb) => match map.display_handle.map_dumb_framebuffer(fb, width, height) { 73 | Ok(mut new_map) => { 74 | let count = new_map.ptr().len(); 75 | unsafe { 76 | ptr::write_bytes(new_map.ptr_mut() as *mut u32, 0, count); 77 | } 78 | 79 | text_screen.resize( 80 | &mut console_draw::DisplayMap { 81 | offscreen: map.inner.ptr_mut(), 82 | width: map.inner.width(), 83 | height: map.inner.height(), 84 | }, 85 | &mut console_draw::DisplayMap { 86 | offscreen: new_map.ptr_mut(), 87 | width: new_map.width(), 88 | height: new_map.height(), 89 | }, 90 | ); 91 | 92 | let _ = map.display_handle.destroy_dumb_framebuffer(map.fb); 93 | 94 | map.fb = fb; 95 | map.inner = new_map; 96 | 97 | log::debug!("fbcond: mapped display"); 98 | } 99 | Err(err) => { 100 | log::error!("fbcond: failed to open display: {}", err); 101 | } 102 | }, 103 | Err(err) => { 104 | log::error!("fbcond: failed to create framebuffer: {}", err); 105 | } 106 | } 107 | } 108 | } 109 | 110 | pub fn sync_rect(&mut self, damage: Damage) { 111 | if let Some(map) = &self.map { 112 | map.display_handle.update_plane(0, map.fb, damage).unwrap(); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /graphics/vesad/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate orbclient; 2 | extern crate syscall; 3 | 4 | use driver_graphics::GraphicsScheme; 5 | use event::{user_data, EventQueue}; 6 | use inputd::DisplayHandle; 7 | use std::env; 8 | use std::os::fd::AsRawFd; 9 | 10 | use crate::scheme::{FbAdapter, FrameBuffer}; 11 | 12 | mod scheme; 13 | 14 | fn main() { 15 | if env::var("FRAMEBUFFER_WIDTH").is_err() { 16 | println!("vesad: No boot framebuffer"); 17 | return; 18 | } 19 | 20 | let width = usize::from_str_radix( 21 | &env::var("FRAMEBUFFER_WIDTH").expect("FRAMEBUFFER_WIDTH not set"), 22 | 16, 23 | ) 24 | .expect("failed to parse FRAMEBUFFER_WIDTH"); 25 | let height = usize::from_str_radix( 26 | &env::var("FRAMEBUFFER_HEIGHT").expect("FRAMEBUFFER_HEIGHT not set"), 27 | 16, 28 | ) 29 | .expect("failed to parse FRAMEBUFFER_HEIGHT"); 30 | let phys = usize::from_str_radix( 31 | &env::var("FRAMEBUFFER_ADDR").expect("FRAMEBUFFER_ADDR not set"), 32 | 16, 33 | ) 34 | .expect("failed to parse FRAMEBUFFER_ADDR"); 35 | let stride = usize::from_str_radix( 36 | &env::var("FRAMEBUFFER_STRIDE").expect("FRAMEBUFFER_STRIDE not set"), 37 | 16, 38 | ) 39 | .expect("failed to parse FRAMEBUFFER_STRIDE"); 40 | 41 | println!( 42 | "vesad: {}x{} stride {} at 0x{:X}", 43 | width, height, stride, phys 44 | ); 45 | 46 | if phys == 0 { 47 | println!("vesad: Boot framebuffer at address 0"); 48 | return; 49 | } 50 | 51 | let mut framebuffers = vec![unsafe { FrameBuffer::new(phys, width, height, stride) }]; 52 | 53 | //TODO: ideal maximum number of outputs? 54 | for i in 1..1024 { 55 | match env::var(&format!("FRAMEBUFFER{}", i)) { 56 | Ok(var) => match unsafe { FrameBuffer::parse(&var) } { 57 | Some(fb) => { 58 | println!( 59 | "vesad: framebuffer {}: {}x{} stride {} at 0x{:X}", 60 | i, fb.width, fb.height, fb.stride, fb.phys 61 | ); 62 | framebuffers.push(fb); 63 | } 64 | None => { 65 | eprintln!("vesad: framebuffer {}: failed to parse '{}'", i, var); 66 | } 67 | }, 68 | Err(_err) => break, 69 | }; 70 | } 71 | 72 | redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers)) 73 | .expect("failed to create daemon"); 74 | } 75 | fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { 76 | let mut inputd_display_handle = DisplayHandle::new_early("vesa").unwrap(); 77 | 78 | let mut scheme = GraphicsScheme::new(FbAdapter { framebuffers }, "display.vesa".to_owned()); 79 | 80 | user_data! { 81 | enum Source { 82 | Input, 83 | Scheme, 84 | } 85 | } 86 | 87 | let event_queue: EventQueue = 88 | EventQueue::new().expect("vesad: failed to create event queue"); 89 | event_queue 90 | .subscribe( 91 | inputd_display_handle.inner().as_raw_fd() as usize, 92 | Source::Input, 93 | event::EventFlags::READ, 94 | ) 95 | .unwrap(); 96 | event_queue 97 | .subscribe( 98 | scheme.event_handle().raw(), 99 | Source::Scheme, 100 | event::EventFlags::READ, 101 | ) 102 | .unwrap(); 103 | 104 | libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); 105 | 106 | daemon.ready().expect("failed to notify parent"); 107 | 108 | let all = [Source::Input, Source::Scheme]; 109 | for event in all 110 | .into_iter() 111 | .chain(event_queue.map(|e| e.expect("vesad: failed to get next event").user_data)) 112 | { 113 | match event { 114 | Source::Input => { 115 | while let Some(vt_event) = inputd_display_handle 116 | .read_vt_event() 117 | .expect("vesad: failed to read display handle") 118 | { 119 | scheme.handle_vt_event(vt_event); 120 | } 121 | } 122 | Source::Scheme => { 123 | scheme 124 | .tick() 125 | .expect("vesad: failed to handle scheme events"); 126 | } 127 | } 128 | } 129 | 130 | panic!(); 131 | } 132 | -------------------------------------------------------------------------------- /storage/nvmed/src/nvme/queues.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::ptr; 3 | use syscall::Result; 4 | 5 | use common::dma::Dma; 6 | 7 | /// A submission queue entry. 8 | #[derive(Clone, Copy, Debug, Default)] 9 | #[repr(C, packed)] 10 | pub struct NvmeCmd { 11 | /// Opcode 12 | pub opcode: u8, 13 | /// Flags 14 | pub flags: u8, 15 | /// Command ID 16 | pub cid: u16, 17 | /// Namespace identifier 18 | pub nsid: u32, 19 | /// Reserved 20 | pub _rsvd: u64, 21 | /// Metadata pointer 22 | pub mptr: u64, 23 | /// Data pointer 24 | pub dptr: [u64; 2], 25 | /// Command dword 10 26 | pub cdw10: u32, 27 | /// Command dword 11 28 | pub cdw11: u32, 29 | /// Command dword 12 30 | pub cdw12: u32, 31 | /// Command dword 13 32 | pub cdw13: u32, 33 | /// Command dword 14 34 | pub cdw14: u32, 35 | /// Command dword 15 36 | pub cdw15: u32, 37 | } 38 | 39 | /// A completion queue entry. 40 | #[derive(Clone, Copy, Debug)] 41 | #[repr(C, packed)] 42 | pub struct NvmeComp { 43 | pub command_specific: u32, 44 | pub _rsvd: u32, 45 | pub sq_head: u16, 46 | pub sq_id: u16, 47 | pub cid: u16, 48 | pub status: u16, 49 | } 50 | 51 | /// Completion queue 52 | pub struct NvmeCompQueue { 53 | pub data: Dma<[UnsafeCell]>, 54 | pub head: u16, 55 | pub phase: bool, 56 | } 57 | 58 | impl NvmeCompQueue { 59 | pub fn new() -> Result { 60 | Ok(Self { 61 | data: unsafe { Dma::zeroed_slice(256)?.assume_init() }, 62 | head: 0, 63 | phase: true, 64 | }) 65 | } 66 | 67 | /// Get a new completion queue entry, or return None if no entry is available yet. 68 | pub(crate) fn complete(&mut self) -> Option<(u16, NvmeComp)> { 69 | let entry = unsafe { ptr::read_volatile(self.data[usize::from(self.head)].get()) }; 70 | 71 | if ((entry.status & 1) == 1) == self.phase { 72 | self.head = (self.head + 1) % (self.data.len() as u16); 73 | if self.head == 0 { 74 | self.phase = !self.phase; 75 | } 76 | Some((self.head, entry)) 77 | } else { 78 | None 79 | } 80 | } 81 | 82 | /// Get a new CQ entry, busy waiting until an entry appears. 83 | pub fn complete_spin(&mut self) -> (u16, NvmeComp) { 84 | log::debug!("Waiting for new CQ entry"); 85 | loop { 86 | if let Some(some) = self.complete() { 87 | return some; 88 | } else { 89 | unsafe { 90 | std::hint::spin_loop(); 91 | } 92 | } 93 | } 94 | } 95 | } 96 | 97 | /// Submission queue 98 | pub struct NvmeCmdQueue { 99 | pub data: Dma<[UnsafeCell]>, 100 | pub tail: u16, 101 | pub head: u16, 102 | } 103 | 104 | impl NvmeCmdQueue { 105 | pub fn new() -> Result { 106 | Ok(Self { 107 | data: unsafe { Dma::zeroed_slice(64)?.assume_init() }, 108 | tail: 0, 109 | head: 0, 110 | }) 111 | } 112 | 113 | pub fn is_empty(&self) -> bool { 114 | self.head == self.tail 115 | } 116 | pub fn is_full(&self) -> bool { 117 | self.head == self.tail + 1 118 | } 119 | 120 | /// Add a new submission command entry to the queue. The caller must ensure that the queue have free 121 | /// entries; this can be checked using `is_full`. 122 | pub fn submit_unchecked(&mut self, entry: NvmeCmd) -> u16 { 123 | unsafe { ptr::write_volatile(self.data[usize::from(self.tail)].get(), entry) } 124 | self.tail = (self.tail + 1) % (self.data.len() as u16); 125 | self.tail 126 | } 127 | } 128 | 129 | #[derive(Debug)] 130 | pub enum Status { 131 | GenericCmdStatus(u8), 132 | CommandSpecificStatus(u8), 133 | IntegrityError(u8), 134 | PathRelatedStatus(u8), 135 | Rsvd(u8), 136 | Vendor(u8), 137 | } 138 | impl Status { 139 | pub fn parse(raw: u16) -> Self { 140 | let code = (raw >> 1) as u8; 141 | match (raw >> 9) & 0b111 { 142 | 0 => Self::GenericCmdStatus(code), 143 | 1 => Self::CommandSpecificStatus(code), 144 | 2 => Self::IntegrityError(code), 145 | 3 => Self::PathRelatedStatus(code), 146 | 4..=6 => Self::Rsvd(code), 147 | 7 => Self::Vendor(code), 148 | _ => unreachable!(), 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /rtcd/src/x86.rs: -------------------------------------------------------------------------------- 1 | // TODO: Get RTC information from acpid. 2 | use common::io::{Io, Pio}; 3 | 4 | pub fn get_time() -> u64 { 5 | Rtc::new().time() 6 | } 7 | 8 | fn cvt_bcd(value: usize) -> usize { 9 | (value & 0xF) + ((value / 16) * 10) 10 | } 11 | 12 | /// RTC 13 | pub struct Rtc { 14 | addr: Pio, 15 | data: Pio, 16 | nmi: bool, 17 | } 18 | 19 | impl Rtc { 20 | /// Create new empty RTC 21 | pub fn new() -> Self { 22 | Rtc { 23 | addr: Pio::::new(0x70), 24 | data: Pio::::new(0x71), 25 | nmi: false, 26 | } 27 | } 28 | 29 | /// Read 30 | unsafe fn read(&mut self, reg: u8) -> u8 { 31 | if self.nmi { 32 | self.addr.write(reg & 0x7F); 33 | } else { 34 | self.addr.write(reg | 0x80); 35 | } 36 | self.data.read() 37 | } 38 | 39 | /// Write 40 | #[allow(dead_code)] 41 | unsafe fn write(&mut self, reg: u8, value: u8) { 42 | if self.nmi { 43 | self.addr.write(reg & 0x7F); 44 | } else { 45 | self.addr.write(reg | 0x80); 46 | } 47 | self.data.write(value); 48 | } 49 | 50 | /// Wait for an update, can take one second if full is specified! 51 | unsafe fn wait(&mut self, full: bool) { 52 | if full { 53 | while self.read(0xA) & 0x80 != 0x80 {} 54 | } 55 | while self.read(0xA) & 0x80 == 0x80 {} 56 | } 57 | 58 | /// Get time without waiting 59 | pub unsafe fn time_no_wait(&mut self) -> u64 { 60 | /*let century_register = if let Some(ref fadt) = acpi::ACPI_TABLE.lock().fadt { 61 | Some(fadt.century) 62 | } else { 63 | None 64 | };*/ 65 | 66 | let mut second = self.read(0) as usize; 67 | let mut minute = self.read(2) as usize; 68 | let mut hour = self.read(4) as usize; 69 | let mut day = self.read(7) as usize; 70 | let mut month = self.read(8) as usize; 71 | let mut year = self.read(9) as usize; 72 | let mut century = /* TODO: Fix invalid value from VirtualBox 73 | if let Some(century_reg) = century_register { 74 | self.read(century_reg) as usize 75 | } else */ { 76 | 20 77 | }; 78 | let register_b = self.read(0xB); 79 | 80 | if register_b & 4 != 4 { 81 | second = cvt_bcd(second); 82 | minute = cvt_bcd(minute); 83 | hour = cvt_bcd(hour & 0x7F) | (hour & 0x80); 84 | day = cvt_bcd(day); 85 | month = cvt_bcd(month); 86 | year = cvt_bcd(year); 87 | century = /* TODO: Fix invalid value from VirtualBox 88 | if century_register.is_some() { 89 | cvt_bcd(century) 90 | } else */ { 91 | century 92 | }; 93 | } 94 | 95 | if register_b & 2 != 2 || hour & 0x80 == 0x80 { 96 | hour = ((hour & 0x7F) + 12) % 24; 97 | } 98 | 99 | year += century * 100; 100 | 101 | // Unix time from clock 102 | let mut secs: u64 = (year as u64 - 1970) * 31_536_000; 103 | 104 | let mut leap_days = (year as u64 - 1972) / 4 + 1; 105 | if year % 4 == 0 && month <= 2 { 106 | leap_days -= 1; 107 | } 108 | secs += leap_days * 86_400; 109 | 110 | match month { 111 | 2 => secs += 2_678_400, 112 | 3 => secs += 5_097_600, 113 | 4 => secs += 7_776_000, 114 | 5 => secs += 10_368_000, 115 | 6 => secs += 13_046_400, 116 | 7 => secs += 15_638_400, 117 | 8 => secs += 18_316_800, 118 | 9 => secs += 20_995_200, 119 | 10 => secs += 23_587_200, 120 | 11 => secs += 26_265_600, 121 | 12 => secs += 28_857_600, 122 | _ => (), 123 | } 124 | 125 | secs += (day as u64 - 1) * 86_400; 126 | secs += hour as u64 * 3600; 127 | secs += minute as u64 * 60; 128 | secs += second as u64; 129 | 130 | secs 131 | } 132 | 133 | /// Get time 134 | pub fn time(&mut self) -> u64 { 135 | loop { 136 | unsafe { 137 | self.wait(false); 138 | let time = self.time_no_wait(); 139 | self.wait(false); 140 | let next_time = self.time_no_wait(); 141 | if time == next_time { 142 | return time; 143 | } 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /input/ps2d/src/scheme.rs: -------------------------------------------------------------------------------- 1 | use redox_scheme::scheme::SchemeSync; 2 | use redox_scheme::{CallerCtx, OpenResult}; 3 | use std::convert::TryFrom; 4 | use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; 5 | use syscall::schemev2::NewFdFlags; 6 | use syscall::{ 7 | Error, Result, EACCES, EINVAL, EMFILE, ENOENT, ENOTDIR, MODE_DIR, MODE_FILE, O_WRONLY, 8 | }; 9 | 10 | pub struct Ps2Scheme { 11 | pub keymap: String, 12 | pub keymap_list: String, 13 | } 14 | 15 | impl Ps2Scheme { 16 | pub fn new(keymap: String, keymap_list: Vec<&str>) -> Ps2Scheme { 17 | let scheme = Ps2Scheme { 18 | keymap, 19 | keymap_list: keymap_list.join("\n"), 20 | }; 21 | scheme 22 | } 23 | } 24 | 25 | impl SchemeSync for Ps2Scheme { 26 | fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { 27 | let path = path_str.trim_start_matches('/'); 28 | if flags & O_WRONLY != 0 { 29 | if ctx.uid != 0 || ctx.gid != 0 { 30 | return Err(Error::new(EACCES)); 31 | } else if path != "keymap" { 32 | return Err(Error::new(EINVAL)); 33 | } 34 | } 35 | 36 | match path { 37 | "" => Ok(OpenResult::ThisScheme { 38 | number: 0, 39 | flags: NewFdFlags::empty(), 40 | }), 41 | "keymap" => Ok(OpenResult::ThisScheme { 42 | number: 1, 43 | flags: NewFdFlags::POSITIONED, 44 | }), 45 | "keymap_list" => Ok(OpenResult::ThisScheme { 46 | number: 2, 47 | flags: NewFdFlags::POSITIONED, 48 | }), 49 | _ => Err(Error::new(ENOENT)), 50 | } 51 | } 52 | fn getdents<'buf>( 53 | &mut self, 54 | id: usize, 55 | mut buf: DirentBuf<&'buf mut [u8]>, 56 | opaque_offset: u64, 57 | ) -> Result> { 58 | if id != 0 { 59 | return Err(Error::new(ENOTDIR)); 60 | } 61 | let Ok(offset) = usize::try_from(opaque_offset) else { 62 | return Ok(buf); 63 | }; 64 | for (this_idx, name) in ["keymap", "keymap_list"].iter().enumerate().skip(offset) { 65 | buf.entry(DirEntry { 66 | inode: this_idx as u64, 67 | next_opaque_id: this_idx as u64 + 1, 68 | kind: DirentKind::Regular, 69 | name, 70 | })?; 71 | } 72 | Ok(buf) 73 | } 74 | 75 | fn fstat(&mut self, id: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> { 76 | stat.st_size = 0; 77 | stat.st_mode = match id { 78 | 0 => 0o555 | MODE_DIR, 79 | 1 => 0o644 | MODE_FILE, 80 | 2 => 0o444 | MODE_FILE, 81 | _ => return Err(Error::new(ENOENT)), 82 | }; 83 | Ok(()) 84 | } 85 | 86 | fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { 87 | let path = b"/scheme/ps2"; 88 | 89 | let mut i = 0; 90 | while i < buf.len() && i < path.len() { 91 | buf[i] = path[i]; 92 | i += 1; 93 | } 94 | 95 | Ok(i) 96 | } 97 | 98 | fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { 99 | Ok(()) 100 | } 101 | 102 | fn read( 103 | &mut self, 104 | id: usize, 105 | buf: &mut [u8], 106 | offset: u64, 107 | _fcntl_flags: u32, 108 | _ctx: &CallerCtx, 109 | ) -> Result { 110 | if offset != 0 { 111 | return Ok(0); 112 | } 113 | let value = match id { 114 | 1 => self.keymap.as_bytes(), 115 | 2 => self.keymap_list.as_bytes(), 116 | _ => { 117 | return Err(Error::new(ENOENT)); 118 | } 119 | }; 120 | 121 | if buf.len() + 2 < value.len() { 122 | return Err(Error::new(EMFILE)); 123 | } 124 | buf[..value.len()].copy_from_slice(value); 125 | buf[value.len()] = b'\n'; 126 | buf[value.len() + 1] = b'\0'; 127 | Ok(value.len() + 2) 128 | } 129 | 130 | fn write( 131 | &mut self, 132 | id: usize, 133 | buf: &[u8], 134 | offset: u64, 135 | _fcntl_flags: u32, 136 | _ctx: &CallerCtx, 137 | ) -> Result { 138 | if offset != 0 || id != 1 { 139 | return Ok(0); 140 | } 141 | let new_keymap = String::from_utf8(buf.to_vec()).map_err(|_| Error::new(EINVAL))?; 142 | self.keymap = new_keymap.trim().to_string(); 143 | Ok(buf.len()) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /storage/nvmed/src/nvme/cmd.rs: -------------------------------------------------------------------------------- 1 | use super::NvmeCmd; 2 | 3 | impl NvmeCmd { 4 | pub fn create_io_completion_queue( 5 | cid: u16, 6 | qid: u16, 7 | ptr: usize, 8 | size: u16, 9 | iv: Option, 10 | ) -> Self { 11 | const DW11_PHYSICALLY_CONTIGUOUS_BIT: u32 = 0x0000_0001; 12 | const DW11_ENABLE_INTERRUPTS_BIT: u32 = 0x0000_0002; 13 | const DW11_INTERRUPT_VECTOR_SHIFT: u8 = 16; 14 | 15 | Self { 16 | opcode: 5, 17 | flags: 0, 18 | cid, 19 | nsid: 0, 20 | _rsvd: 0, 21 | mptr: 0, 22 | dptr: [ptr as u64, 0], 23 | cdw10: ((size as u32) << 16) | (qid as u32), 24 | 25 | cdw11: DW11_PHYSICALLY_CONTIGUOUS_BIT 26 | | if let Some(iv) = iv { 27 | // enable interrupts if a vector is present 28 | DW11_ENABLE_INTERRUPTS_BIT | (u32::from(iv) << DW11_INTERRUPT_VECTOR_SHIFT) 29 | } else { 30 | 0 31 | }, 32 | 33 | cdw12: 0, 34 | cdw13: 0, 35 | cdw14: 0, 36 | cdw15: 0, 37 | } 38 | } 39 | 40 | pub fn create_io_submission_queue( 41 | cid: u16, 42 | qid: u16, 43 | ptr: usize, 44 | size: u16, 45 | cqid: u16, 46 | ) -> Self { 47 | Self { 48 | opcode: 1, 49 | flags: 0, 50 | cid, 51 | nsid: 0, 52 | _rsvd: 0, 53 | mptr: 0, 54 | dptr: [ptr as u64, 0], 55 | cdw10: ((size as u32) << 16) | (qid as u32), 56 | cdw11: ((cqid as u32) << 16) | 1, /* Physically Contiguous */ 57 | //TODO: QPRIO 58 | cdw12: 0, //TODO: NVMSETID 59 | cdw13: 0, 60 | cdw14: 0, 61 | cdw15: 0, 62 | } 63 | } 64 | 65 | pub fn identify_namespace(cid: u16, ptr: usize, nsid: u32) -> Self { 66 | Self { 67 | opcode: 6, 68 | flags: 0, 69 | cid, 70 | nsid, 71 | _rsvd: 0, 72 | mptr: 0, 73 | dptr: [ptr as u64, 0], 74 | cdw10: 0, 75 | cdw11: 0, 76 | cdw12: 0, 77 | cdw13: 0, 78 | cdw14: 0, 79 | cdw15: 0, 80 | } 81 | } 82 | 83 | pub fn identify_controller(cid: u16, ptr: usize) -> Self { 84 | Self { 85 | opcode: 6, 86 | flags: 0, 87 | cid, 88 | nsid: 0, 89 | _rsvd: 0, 90 | mptr: 0, 91 | dptr: [ptr as u64, 0], 92 | cdw10: 1, 93 | cdw11: 0, 94 | cdw12: 0, 95 | cdw13: 0, 96 | cdw14: 0, 97 | cdw15: 0, 98 | } 99 | } 100 | 101 | pub fn identify_namespace_list(cid: u16, ptr: usize, base: u32) -> Self { 102 | Self { 103 | opcode: 6, 104 | flags: 0, 105 | cid, 106 | nsid: base, 107 | _rsvd: 0, 108 | mptr: 0, 109 | dptr: [ptr as u64, 0], 110 | cdw10: 2, 111 | cdw11: 0, 112 | cdw12: 0, 113 | cdw13: 0, 114 | cdw14: 0, 115 | cdw15: 0, 116 | } 117 | } 118 | pub fn get_features(cid: u16, ptr: usize, fid: u8) -> Self { 119 | Self { 120 | opcode: 0xA, 121 | dptr: [ptr as u64, 0], 122 | cdw10: u32::from(fid), // TODO: SEL 123 | ..Default::default() 124 | } 125 | } 126 | 127 | pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { 128 | Self { 129 | opcode: 2, 130 | flags: 0, 131 | cid, 132 | nsid, 133 | _rsvd: 0, 134 | mptr: 0, 135 | dptr: [ptr0, ptr1], 136 | cdw10: lba as u32, 137 | cdw11: (lba >> 32) as u32, 138 | cdw12: blocks_1 as u32, 139 | cdw13: 0, 140 | cdw14: 0, 141 | cdw15: 0, 142 | } 143 | } 144 | 145 | pub fn io_write(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { 146 | Self { 147 | opcode: 1, 148 | flags: 0, 149 | cid, 150 | nsid, 151 | _rsvd: 0, 152 | mptr: 0, 153 | dptr: [ptr0, ptr1], 154 | cdw10: lba as u32, 155 | cdw11: (lba >> 32) as u32, 156 | cdw12: blocks_1 as u32, 157 | cdw13: 0, 158 | cdw14: 0, 159 | cdw15: 0, 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /audio/ac97d/src/main.rs: -------------------------------------------------------------------------------- 1 | //#![deny(warnings)] 2 | 3 | extern crate bitflags; 4 | extern crate event; 5 | extern crate spin; 6 | extern crate syscall; 7 | 8 | use std::io::{Read, Write}; 9 | use std::os::unix::io::AsRawFd; 10 | use std::usize; 11 | 12 | use event::{user_data, EventQueue}; 13 | use pcid_interface::PciFunctionHandle; 14 | use redox_scheme::wrappers::ReadinessBased; 15 | use redox_scheme::Socket; 16 | use std::cell::RefCell; 17 | 18 | pub mod device; 19 | 20 | fn main() { 21 | let pcid_handle = PciFunctionHandle::connect_default(); 22 | let pci_config = pcid_handle.config(); 23 | 24 | let mut name = pci_config.func.name(); 25 | name.push_str("_ac97"); 26 | 27 | let bar0 = pci_config.func.bars[0].expect_port(); 28 | let bar1 = pci_config.func.bars[1].expect_port(); 29 | 30 | let irq = pci_config 31 | .func 32 | .legacy_interrupt_line 33 | .expect("ac97d: no legacy interrupts supported"); 34 | 35 | println!(" + ac97 {}", pci_config.func.display()); 36 | 37 | // Daemonize 38 | redox_daemon::Daemon::new(move |daemon| { 39 | common::setup_logging( 40 | "audio", 41 | "pci", 42 | &name, 43 | common::output_level(), 44 | common::file_level(), 45 | ); 46 | 47 | common::acquire_port_io_rights() 48 | .expect("ac97d: failed to set I/O privilege level to Ring 3"); 49 | 50 | let mut irq_file = irq.irq_handle("ac97d"); 51 | 52 | let device = RefCell::new(unsafe { 53 | device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") 54 | }); 55 | let socket = Socket::nonblock("audiohw").expect("ac97d: failed to create socket"); 56 | let mut readiness_based = ReadinessBased::new(&socket, 16); 57 | 58 | user_data! { 59 | enum Source { 60 | Irq, 61 | Scheme, 62 | } 63 | } 64 | 65 | let event_queue = 66 | EventQueue::::new().expect("ac97d: Could not create event queue."); 67 | event_queue 68 | .subscribe( 69 | irq_file.as_raw_fd() as usize, 70 | Source::Irq, 71 | event::EventFlags::READ, 72 | ) 73 | .unwrap(); 74 | event_queue 75 | .subscribe( 76 | socket.inner().raw(), 77 | Source::Scheme, 78 | event::EventFlags::READ, 79 | ) 80 | .unwrap(); 81 | 82 | daemon.ready().expect("ac97d: failed to signal readiness"); 83 | 84 | libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace"); 85 | 86 | let all = [Source::Irq, Source::Scheme]; 87 | for event in all 88 | .into_iter() 89 | .chain(event_queue.map(|e| e.expect("ac97d: failed to get next event").user_data)) 90 | { 91 | match event { 92 | Source::Irq => { 93 | let mut irq = [0; 8]; 94 | irq_file.read(&mut irq).unwrap(); 95 | 96 | if !device.borrow_mut().irq() { 97 | continue; 98 | } 99 | irq_file.write(&mut irq).unwrap(); 100 | 101 | readiness_based 102 | .poll_all_requests(|| device.borrow_mut()) 103 | .expect("ac97d: failed to poll requests"); 104 | 105 | /* 106 | let next_read = device_irq.next_read(); 107 | if next_read > 0 { 108 | return Ok(Some(next_read)); 109 | } 110 | */ 111 | } 112 | Source::Scheme => { 113 | if !readiness_based 114 | .read_requests() 115 | .expect("ac97d: failed to read from socket") 116 | { 117 | break; 118 | } 119 | readiness_based.process_requests(|| device.borrow_mut()); 120 | if !readiness_based 121 | .write_responses() 122 | .expect("ac97d: failed to write to socket") 123 | { 124 | break; 125 | } 126 | 127 | /* 128 | let next_read = device.borrow().next_read(); 129 | if next_read > 0 { 130 | return Ok(Some(next_read)); 131 | } 132 | */ 133 | } 134 | } 135 | } 136 | 137 | std::process::exit(0); 138 | }) 139 | .expect("ac97d: failed to daemonize"); 140 | } 141 | -------------------------------------------------------------------------------- /COMMUNITY-HW.md: -------------------------------------------------------------------------------- 1 | # Community Hardware 2 | 3 | This document covers the devices from the community that needs a driver. 4 | 5 | Unfortunately we can't know the most sold device models of the world to measure our device porting priority, thus we will use our community data to measure our device priorities, if you find a "device model users" survey (similar to [Debian Popularity Contest](https://popcon.debian.org/) and [Steam Hardware/Software Survey](https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam)), please comment. 6 | 7 | If you want to contribute to this table, install [pciutils](https://mj.ucw.cz/sw/pciutils/) on your Linux distribution (it should have a package on your distribution), run `lspci -v` to see your hardware devices, their kernel drivers and give the results of these items on each device: 8 | 9 | - The first field (each device has an unique name for this item) 10 | - Kernel driver in use 11 | - Kernel modules 12 | 13 | If you are unsure of what to do, you can talk with us on the [chat](https://doc.redox-os.org/book/chat.html). 14 | 15 | ## Template 16 | 17 | You will use this template to insert your devices on the table. 18 | 19 | ``` 20 | | | | | No | 21 | ``` 22 | 23 | | **Device model** | **Kernel driver** | **Kernel module** | **There's a Redox driver?** | 24 | |------------------|-------------------|-------------------|-----------------------------| 25 | | Realtek RTL8821CE 802.11ac (Wi-Fi) | rtw_8821ce | rtw88_8821ce | No | 26 | | Intel Ice Lake-LP SPI Controller | intel-spi | spi_intel_pci | No | 27 | | Intel Ice Lake-LP SMBus Controller | i801_smbus | i2c_i801 | No | 28 | | Intel Ice Lake-LP Smart Sound Technology Audio Controller | snd_hda_intel | snd_hda_intel, snd_sof_pci_intel_icl | No | 29 | | Intel Ice Lake-LP Serial IO SPI Controller | intel-lpss | No | No | 30 | | Intel Ice Lake-LP Serial IO UART Controller | intel-lpss | No | No | 31 | | Intel Ice Lake-LP Serial IO I2C Controller | intel-lpss | No | No | 32 | | Ice Lake-LP USB 3.1 xHCI Host Controller | xhci_hcd | No | No | 33 | | Intel Processor Power and Thermal Controller | proc_thermal | processor_thermal_device_pci_legacy | No | 34 | | Intel Device 8a02 | icl_uncore | No | No | 35 | | Iris Plus Graphics G1 (Ice Lake) | i915 | i915 | No | 36 | | Intel Corporation Raptor Lake-P 6p+8e cores Host Bridge/DRAM Controller | No | No | No | 37 | | Intel Corporation Raptor Lake PCI Express 5.0 Graphics Port (PEG010) (prog-if 00 [Normal decode]) | pcieport | No | No | 38 | | Intel Corporation Raptor Lake-P [UHD Graphics] (rev 04) (prog-if 00 [VGA controller]) | i915 | i915 | No | 39 | | Intel Corporation Raptor Lake Dynamic Platform and Thermal Framework Processor Participant | proc_thermal_pci | processor_thermal_device_pci | No | 40 | | Intel Corporation Raptor Lake PCIe 4.0 Graphics Port (prog-if 00 [Normal decode]) | pcieport | No | No | 41 | | Intel Corporation Raptor Lake-P Thunderbolt 4 PCI Express Root Port #0 (prog-if 00 [Normal decode]) | pcieport | No | No | 42 | | Intel Corporation GNA Scoring Accelerator module | No | No | No | 43 | | Intel Corporation Raptor Lake-P Thunderbolt 4 USB Controller (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No | 44 | | Intel Corporation Raptor Lake-P Thunderbolt 4 NHI #0 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No | 45 | | Intel Corporation Raptor Lake-P Thunderbolt 4 NHI #1 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No | 46 | | Intel Corporation Alder Lake PCH USB 3.2 xHCI Host Controller (rev 01) (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No | 47 | | Intel Corporation Alder Lake PCH Shared SRAM (rev 01) | No | No | No | 48 | | Intel Corporation Raptor Lake PCH CNVi WiFi (rev 01) | iwlwifi | iwlwifi | No | 49 | | Intel Corporation Alder Lake PCH Serial IO I2C Controller #0 (rev 01) | intel-lpss | intel_lpss_pci | No | 50 | | Intel Corporation Alder Lake PCH HECI Controller (rev 01) | mei_me | mei_me | No | 51 | | Intel Corporation Device 51b8 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No | 52 | | Intel Corporation Alder Lake-P PCH PCIe Root Port #6 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No | 53 | | Intel Corporation Raptor Lake LPC/eSPI Controller (rev 01) | No | No | No | 54 | | Intel Corporation Raptor Lake-P/U/H cAVS (rev 01) (prog-if 80) | sof-audio-pci-intel-tgl | snd_hda_intel, snd_sof_pci_intel_tgl | No | 55 | | Intel Corporation Alder Lake PCH-P SMBus Host Controller | i801_smbus | i2c_i801 | No | 56 | | Intel Corporation Alder Lake-P PCH SPI Controller (rev 01) | intel-spi | spi_intel_pci | No | 57 | | NVIDIA Corporation GA107GLM [RTX A1000 6GB Laptop GPU] (rev a1) | nvidia | nouveau, nvidia_drm, nvidia | No | 58 | | SK hynix Platinum P41/PC801 NVMe Solid State Drive (prog-if 02 [NVM Express]) | nvme | nvme | No | 59 | | Realtek Semiconductor Co., Ltd. RTS5261 PCI Express Card Reader (rev 01) | rtsx_pci | rtsx_pci | No | 60 | 61 | 65 | --------------------------------------------------------------------------------