From 565b4ccd854b2fe1b340c593c2dfdb0e117a7327 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 25 Nov 2023 11:47:35 +0900 Subject: [PATCH 001/115] Add the test project --- .gitignore | 2 +- test/Cargo.toml | 8 ++++++++ test/src/main.rs | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 test/Cargo.toml create mode 100644 test/src/main.rs diff --git a/.gitignore b/.gitignore index 260b90f8..cab2da82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target +target tags **/*.swp **/*.swo diff --git a/test/Cargo.toml b/test/Cargo.toml new file mode 100644 index 00000000..9abbb720 --- /dev/null +++ b/test/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "xhci-test" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/test/src/main.rs b/test/src/main.rs new file mode 100644 index 00000000..e7a11a96 --- /dev/null +++ b/test/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From fca5847b7d14e436ddd7d710d97641f2951014a8 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 25 Nov 2023 11:51:18 +0900 Subject: [PATCH 002/115] Add the build target config --- test/x86_64-unknown-xhcios.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 test/x86_64-unknown-xhcios.json diff --git a/test/x86_64-unknown-xhcios.json b/test/x86_64-unknown-xhcios.json new file mode 100644 index 00000000..74617137 --- /dev/null +++ b/test/x86_64-unknown-xhcios.json @@ -0,0 +1,18 @@ +{ + "arch": "x86_64", + "data-layout": "e-m:e-i64:64-n8:16:32:64-S128", + "llvm-target": "x86_64-unknown-none", + "executables": true, + "features": "-sse,+soft-float", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "code-model": "kernel", + "relocation-model": "static", + "archive-format": "gnu", + "panic-strategy": "abort", + "linker-flavor": "ld", + "linker-is-gnu": true, + "disable-redzone": true +} From 5f1b8ba4477a375d516dd289e60d0c0fa6feaed3 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 25 Nov 2023 11:53:09 +0900 Subject: [PATCH 003/115] Add the cargo config --- test/.cargo/config.toml | 6 ++++++ ...86_64-unknown-xhcios.json => x86_64-unknowntestios.json} | 0 2 files changed, 6 insertions(+) create mode 100644 test/.cargo/config.toml rename test/{x86_64-unknown-xhcios.json => x86_64-unknowntestios.json} (100%) diff --git a/test/.cargo/config.toml b/test/.cargo/config.toml new file mode 100644 index 00000000..7486d677 --- /dev/null +++ b/test/.cargo/config.toml @@ -0,0 +1,6 @@ +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] +build-std-features = ["compiler-builtins-mem"] + +[build] +target = "../x86_64-unknown-testos.json" diff --git a/test/x86_64-unknown-xhcios.json b/test/x86_64-unknowntestios.json similarity index 100% rename from test/x86_64-unknown-xhcios.json rename to test/x86_64-unknowntestios.json From b1936d695ae4cd05eeed5266cbe32c714921826d Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 25 Nov 2023 11:53:46 +0900 Subject: [PATCH 004/115] Fix the path --- test/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/.cargo/config.toml b/test/.cargo/config.toml index 7486d677..5fbaceb6 100644 --- a/test/.cargo/config.toml +++ b/test/.cargo/config.toml @@ -3,4 +3,4 @@ build-std = ["core", "compiler_builtins", "alloc"] build-std-features = ["compiler-builtins-mem"] [build] -target = "../x86_64-unknown-testos.json" +target = "x86_64-unknown-testos.json" From 9e7c558c1ebdcc5aa066e155bca4fa61db51d3f1 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 25 Nov 2023 11:54:03 +0900 Subject: [PATCH 005/115] Rename --- test/{x86_64-unknowntestios.json => x86_64-unknown-testios.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{x86_64-unknowntestios.json => x86_64-unknown-testios.json} (100%) diff --git a/test/x86_64-unknowntestios.json b/test/x86_64-unknown-testios.json similarity index 100% rename from test/x86_64-unknowntestios.json rename to test/x86_64-unknown-testios.json From 0f140c3f4dba6456cf896c738a4c0034bec0d370 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 25 Nov 2023 11:54:27 +0900 Subject: [PATCH 006/115] Typo --- test/{x86_64-unknown-testios.json => x86_64-unknown-testos.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{x86_64-unknown-testios.json => x86_64-unknown-testos.json} (100%) diff --git a/test/x86_64-unknown-testios.json b/test/x86_64-unknown-testos.json similarity index 100% rename from test/x86_64-unknown-testios.json rename to test/x86_64-unknown-testos.json From f12c6817362e3a53cea1ee8a78a1d5e57740aa61 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 25 Nov 2023 13:21:55 +0900 Subject: [PATCH 007/115] Build an UEFI image --- test/.cargo/config.toml | 6 +----- test/Cargo.toml | 5 +++-- test/src/main.rs | 19 +++++++++++++++++-- test/x86_64-unknown-testos.json | 18 ------------------ 4 files changed, 21 insertions(+), 27 deletions(-) delete mode 100644 test/x86_64-unknown-testos.json diff --git a/test/.cargo/config.toml b/test/.cargo/config.toml index 5fbaceb6..85d49dcc 100644 --- a/test/.cargo/config.toml +++ b/test/.cargo/config.toml @@ -1,6 +1,2 @@ -[unstable] -build-std = ["core", "compiler_builtins", "alloc"] -build-std-features = ["compiler-builtins-mem"] - [build] -target = "x86_64-unknown-testos.json" +target = "x86_64-unknown-uefi" diff --git a/test/Cargo.toml b/test/Cargo.toml index 9abbb720..c8a977d8 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -3,6 +3,7 @@ name = "xhci-test" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +qemu-exit = "3.0.2" +qemu_print = { version = "0.1.0", features = ["stable"], default-features = false } +uefi = "0.26.0" diff --git a/test/src/main.rs b/test/src/main.rs index e7a11a96..1a067e3d 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,3 +1,18 @@ -fn main() { - println!("Hello, world!"); +#![no_std] +#![no_main] + +use qemu_exit::QEMUExit; + +#[uefi::entry] +fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { + let handler = qemu_exit::X86::new(0xf4, 33); + + handler.exit_success(); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + let handler = qemu_exit::X86::new(0xf4, 33); + + handler.exit_failure(); } diff --git a/test/x86_64-unknown-testos.json b/test/x86_64-unknown-testos.json deleted file mode 100644 index 74617137..00000000 --- a/test/x86_64-unknown-testos.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "arch": "x86_64", - "data-layout": "e-m:e-i64:64-n8:16:32:64-S128", - "llvm-target": "x86_64-unknown-none", - "executables": true, - "features": "-sse,+soft-float", - "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", - "os": "none", - "code-model": "kernel", - "relocation-model": "static", - "archive-format": "gnu", - "panic-strategy": "abort", - "linker-flavor": "ld", - "linker-is-gnu": true, - "disable-redzone": true -} From a3f524004919e25d350812dbc2f5616725b1a2f5 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 27 Nov 2023 11:51:09 +0900 Subject: [PATCH 008/115] Add a `Makefile` --- test/Makefile | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/Makefile diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..4d55d20f --- /dev/null +++ b/test/Makefile @@ -0,0 +1,34 @@ +.PHONY: test clean + +test: build/os.img + qemu-system-x86_64 \ + -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \ + -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \ + -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ + -serial stdio \ + -display none \ + -drive format=raw,file=build/os.img; \ + if [ $$? -eq 33 ];\ + then\ + echo "Test passed";\ + else\ + echo "Test failed";\ + exit 1;\ + fi + +build/os.img: target/x86_64-unknown-uefi/debug/xhci-test.efi build + dd if=/dev/zero of=build/os.img bs=512 count=93750 + mformat -i build/os.img -h 200 -t 500 -s 144:: + mmd -i build/os.img ::/efi + mmd -i build/os.img ::/efi/boot + mcopy -i build/os.img target/x86_64-unknown-uefi/debug/xhci-test.efi ::/efi/boot/bootx64.efi + +target/x86_64-unknown-uefi/debug/xhci-test.efi: src/main.rs + cargo build + +build: + mkdir build + +clean: + rm -rf build + cargo clean From 85c105f47555ff3de339654d245ab003cf2b3c0c Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 27 Nov 2023 11:51:54 +0900 Subject: [PATCH 009/115] Ignores --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index cab2da82..a3a8e6e7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ tags **/*~ *.temp *.lock + +test/build +OVMF_CODE.fd +OVMF_VARS.fd From 073688c0f633129343f98c8033d3d0feebd09300 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 27 Nov 2023 12:13:31 +0900 Subject: [PATCH 010/115] No reboot --- test/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Makefile b/test/Makefile index 4d55d20f..fd0f2e5f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -6,6 +6,7 @@ test: build/os.img -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ -serial stdio \ + -no-reboot \ -display none \ -drive format=raw,file=build/os.img; \ if [ $$? -eq 33 ];\ From d5978b299cb50f50f7e6077cbb88d971fa1db453 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 27 Nov 2023 12:15:27 +0900 Subject: [PATCH 011/115] Introduce variables to `Makefile` --- test/Makefile | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/test/Makefile b/test/Makefile index fd0f2e5f..5f7287a6 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,6 +1,9 @@ +IMG = build/os.img +EFI = target/x86_64-unknown-uefi/debug/xhci-test.efi + .PHONY: test clean -test: build/os.img +test: $(IMG) qemu-system-x86_64 \ -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \ -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \ @@ -8,7 +11,7 @@ test: build/os.img -serial stdio \ -no-reboot \ -display none \ - -drive format=raw,file=build/os.img; \ + -drive format=raw,file=$(IMG); \ if [ $$? -eq 33 ];\ then\ echo "Test passed";\ @@ -17,14 +20,14 @@ test: build/os.img exit 1;\ fi -build/os.img: target/x86_64-unknown-uefi/debug/xhci-test.efi build - dd if=/dev/zero of=build/os.img bs=512 count=93750 - mformat -i build/os.img -h 200 -t 500 -s 144:: - mmd -i build/os.img ::/efi - mmd -i build/os.img ::/efi/boot - mcopy -i build/os.img target/x86_64-unknown-uefi/debug/xhci-test.efi ::/efi/boot/bootx64.efi +$(IMG): $(EFI) build + dd if=/dev/zero of=$@ bs=512 count=93750 + mformat -i $@ -h 200 -t 500 -s 144:: + mmd -i $@ ::/efi + mmd -i $@ ::/efi/boot + mcopy -i $@ $(EFI) ::/efi/boot/bootx64.efi -target/x86_64-unknown-uefi/debug/xhci-test.efi: src/main.rs +$(EFI): cargo build build: From d2c72e0283d9ad262c373ffcdd2ebac334442a7f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 27 Nov 2023 12:15:39 +0900 Subject: [PATCH 012/115] Printing --- test/src/main.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/src/main.rs b/test/src/main.rs index 1a067e3d..b82347f1 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -2,11 +2,18 @@ #![no_main] use qemu_exit::QEMUExit; +use qemu_print::qemu_println; +use uefi::table::boot::MemoryType; #[uefi::entry] fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { - let handler = qemu_exit::X86::new(0xf4, 33); + let (_, memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); + + for descriptor in memory_map.entries() { + qemu_println!("{:?}", descriptor); + } + let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } @@ -14,5 +21,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> fn panic(_info: &core::panic::PanicInfo) -> ! { let handler = qemu_exit::X86::new(0xf4, 33); + qemu_println!("panic: {:?}", _info); + handler.exit_failure(); } From bad635240f1ea8e4c5ea75998be321618566a414 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Thu, 30 Nov 2023 10:19:19 +0900 Subject: [PATCH 013/115] Search a xHC --- test/Cargo.toml | 2 + test/Makefile | 3 +- test/src/main.rs | 12 +++--- test/src/pci.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 test/src/pci.rs diff --git a/test/Cargo.toml b/test/Cargo.toml index c8a977d8..664e791b 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] +bit_field = "0.10.2" qemu-exit = "3.0.2" qemu_print = { version = "0.1.0", features = ["stable"], default-features = false } uefi = "0.26.0" +x86_64 = { version = "0.14.11", default-features = false } diff --git a/test/Makefile b/test/Makefile index 5f7287a6..7db1fc41 100644 --- a/test/Makefile +++ b/test/Makefile @@ -8,6 +8,7 @@ test: $(IMG) -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \ -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ + -device qemu-xhci,id=xhci\ -serial stdio \ -no-reboot \ -display none \ @@ -27,7 +28,7 @@ $(IMG): $(EFI) build mmd -i $@ ::/efi/boot mcopy -i $@ $(EFI) ::/efi/boot/bootx64.efi -$(EFI): +$(EFI): $(wildcard src/*.rs) Cargo.toml cargo build build: diff --git a/test/src/main.rs b/test/src/main.rs index b82347f1..d89bfef4 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -5,23 +5,23 @@ use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; +mod pci; + #[uefi::entry] fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { - let (_, memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); + let (_, _memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); - for descriptor in memory_map.entries() { - qemu_println!("{:?}", descriptor); - } + assert!(pci::xhci_exists(), "xHCI controller not found"); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } #[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { +fn panic(info: &core::panic::PanicInfo) -> ! { let handler = qemu_exit::X86::new(0xf4, 33); - qemu_println!("panic: {:?}", _info); + qemu_println!("{}", info); handler.exit_failure(); } diff --git a/test/src/pci.rs b/test/src/pci.rs new file mode 100644 index 00000000..bce61875 --- /dev/null +++ b/test/src/pci.rs @@ -0,0 +1,105 @@ +use bit_field::BitField; +use qemu_print::qemu_println; +use x86_64::instructions::port::PortRead; +use x86_64::instructions::port::PortWrite; + +pub fn xhci_exists() -> bool { + for device in 0..=31 { + for bus in 0..=255 { + let config_address_reader = unsafe { ConfigSpaceReader::new(0, device, bus) }; + let config_space = unsafe { ConfigSpace::new(config_address_reader) }; + + if config_space.vendor_id() == 0xffff { + continue; + } + + if config_space.base_class() == 0x0c + && config_space.sub_class() == 0x03 + && config_space.interface() == 0x30 + { + return true; + } + } + } + + false +} + +struct ConfigSpace { + address: ConfigSpaceReader, +} +impl ConfigSpace { + /// # Safety + /// + /// `address` must be a valid address. + unsafe fn new(address: ConfigSpaceReader) -> Self { + Self { address } + } + + fn vendor_id(&self) -> u16 { + let result = unsafe { self.address.read(0) }; + + result.get_bits(0..=15) as u16 + } + + fn base_class(&self) -> u8 { + let result = unsafe { self.address.read(2) }; + + result.get_bits(24..=31) as u8 + } + + fn sub_class(&self) -> u8 { + let result = unsafe { self.address.read(2) }; + + result.get_bits(16..=23) as u8 + } + + fn interface(&self) -> u8 { + let result = unsafe { self.address.read(2) }; + + result.get_bits(8..=15) as u8 + } +} + +struct ConfigSpaceReader { + function: u8, + device: u8, + bus: u8, +} +impl ConfigSpaceReader { + const CONFIG_ADDRESS: u16 = 0xcf8; + const CONFIG_DATA: u16 = 0xcfc; + + /// # Safety + /// + /// `function`, `device`, and `bus` must be valid. + unsafe fn new(function: u8, device: u8, bus: u8) -> Self { + assert!(function < 8, "function must be less than 8"); + assert!(device < 32, "device must be less than 32"); + + Self { + function, + device, + bus, + } + } + + unsafe fn read(&self, offset: u8) -> u32 { + assert!(offset < 32, "offset must be less than 32"); + + unsafe { PortWrite::write_to_port(Self::CONFIG_ADDRESS, self.as_u32(offset)) }; + unsafe { PortRead::read_from_port(Self::CONFIG_DATA) } + } + + fn as_u32(&self, offset: u8) -> u32 { + let mut result = 0; + + result.set_bits(2..=7, offset.into()); + result.set_bits(8..=10, self.function.into()); + result.set_bits(11..=15, self.device.into()); + result.set_bits(16..=23, self.bus.into()); + result.set_bit(31, true); + + result + } +} From dc536d2d03e4814420eb04e8f4ade73d09c03e8a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Thu, 30 Nov 2023 10:26:33 +0900 Subject: [PATCH 014/115] Remove an unused import --- test/src/pci.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/src/pci.rs b/test/src/pci.rs index bce61875..f0df881a 100644 --- a/test/src/pci.rs +++ b/test/src/pci.rs @@ -1,5 +1,4 @@ use bit_field::BitField; -use qemu_print::qemu_println; use x86_64::instructions::port::PortRead; use x86_64::instructions::port::PortWrite; From 1088aa4681cd2a4d9c9f23cf91ef7ddb13a58a35 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Thu, 30 Nov 2023 21:31:39 +0900 Subject: [PATCH 015/115] Iterator --- test/src/pci.rs | 60 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/test/src/pci.rs b/test/src/pci.rs index f0df881a..8a8679f0 100644 --- a/test/src/pci.rs +++ b/test/src/pci.rs @@ -3,25 +3,51 @@ use x86_64::instructions::port::PortRead; use x86_64::instructions::port::PortWrite; pub fn xhci_exists() -> bool { - for device in 0..=31 { - for bus in 0..=255 { - let config_address_reader = unsafe { ConfigSpaceReader::new(0, device, bus) }; - let config_space = unsafe { ConfigSpace::new(config_address_reader) }; - - if config_space.vendor_id() == 0xffff { - continue; - } - - if config_space.base_class() == 0x0c - && config_space.sub_class() == 0x03 - && config_space.interface() == 0x30 - { - return true; - } - } + iter_devices() + .find(|device| { + device.base_class() == 0x0c && device.sub_class() == 0x03 && device.interface() == 0x30 + }) + .is_some() +} + +fn iter_devices() -> impl Iterator { + DeviceIter::new() +} + +struct DeviceIter { + device: u8, + bus: u8, +} +impl DeviceIter { + fn new() -> Self { + Self { device: 0, bus: 0 } } +} +impl Iterator for DeviceIter { + type Item = ConfigSpace; - false + fn next(&mut self) -> Option { + if self.device == 32 { + self.device = 0; + + let Some(result) = self.bus.checked_add(1) else { + return None; + }; + + self.bus = result; + } + + let config_address_reader = unsafe { ConfigSpaceReader::new(0, self.device, self.bus) }; + let config_space = unsafe { ConfigSpace::new(config_address_reader) }; + + self.device += 1; + + if config_space.vendor_id() == 0xffff { + return self.next(); + } + + Some(config_space) + } } struct ConfigSpace { From b701c1656a5d99a9265afa82a90ec18fcb022654 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 4 Dec 2023 11:28:01 +0900 Subject: [PATCH 016/115] Access to registers --- test/Cargo.toml | 1 + test/src/main.rs | 21 ++++++++++++++++++++- test/src/pci.rs | 20 +++++++++++++------- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/test/Cargo.toml b/test/Cargo.toml index 664e791b..c188b38f 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -9,3 +9,4 @@ qemu-exit = "3.0.2" qemu_print = { version = "0.1.0", features = ["stable"], default-features = false } uefi = "0.26.0" x86_64 = { version = "0.14.11", default-features = false } +xhci = { version = "0.9.2", path = ".." } diff --git a/test/src/main.rs b/test/src/main.rs index d89bfef4..3b4ffb82 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,17 +1,36 @@ #![no_std] #![no_main] +use core::num::NonZeroUsize; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; mod pci; +#[derive(Clone)] +struct Mapper; +impl xhci::accessor::Mapper for Mapper { + // UEFI sets up the identity mapping, so we don't need to do anything here. + unsafe fn map(&mut self, physical_address: usize, _: usize) -> NonZeroUsize { + NonZeroUsize::new(physical_address).expect("physical_address is zero") + } + + fn unmap(&mut self, _virtual_address: usize, _size: usize) {} +} + #[uefi::entry] fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { let (_, _memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); - assert!(pci::xhci_exists(), "xHCI controller not found"); + let xhc_config_space = pci::iter_xhc().next().expect("xHC not found"); + + let mmio_low = xhc_config_space.base_address_register(0); + let mmio_high = xhc_config_space.base_address_register(1); + + let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; + + let _registers = unsafe { xhci::Registers::new(mmio_base, Mapper) }; let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/pci.rs b/test/src/pci.rs index 8a8679f0..4abd2e25 100644 --- a/test/src/pci.rs +++ b/test/src/pci.rs @@ -2,12 +2,10 @@ use bit_field::BitField; use x86_64::instructions::port::PortRead; use x86_64::instructions::port::PortWrite; -pub fn xhci_exists() -> bool { - iter_devices() - .find(|device| { - device.base_class() == 0x0c && device.sub_class() == 0x03 && device.interface() == 0x30 - }) - .is_some() +pub fn iter_xhc() -> impl Iterator { + iter_devices().filter(|device| { + device.base_class() == 0x0c && device.sub_class() == 0x03 && device.interface() == 0x30 + }) } fn iter_devices() -> impl Iterator { @@ -50,7 +48,7 @@ impl Iterator for DeviceIter { } } -struct ConfigSpace { +pub struct ConfigSpace { address: ConfigSpaceReader, } impl ConfigSpace { @@ -61,6 +59,14 @@ impl ConfigSpace { Self { address } } + pub fn base_address_register(&self, index: u8) -> u32 { + assert!(index < 6, "index must be less than 6"); + + let result = unsafe { self.address.read(4 + index) }; + + result + } + fn vendor_id(&self) -> u16 { let result = unsafe { self.address.read(0) }; From 0769f556fae3611106590279fd41bc3bf2a0c2e7 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 4 Dec 2023 11:45:18 +0900 Subject: [PATCH 017/115] Iterate extended capabilities --- test/src/main.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index 3b4ffb82..b365e5c8 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,14 +1,15 @@ #![no_std] #![no_main] +mod pci; + use core::num::NonZeroUsize; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; +use xhci::extended_capabilities; -mod pci; - -#[derive(Clone)] +#[derive(Clone, Debug)] struct Mapper; impl xhci::accessor::Mapper for Mapper { // UEFI sets up the identity mapping, so we don't need to do anything here. @@ -30,7 +31,21 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; - let _registers = unsafe { xhci::Registers::new(mmio_base, Mapper) }; + let registers = unsafe { xhci::Registers::new(mmio_base, Mapper) }; + + let extended_capabilities = unsafe { + extended_capabilities::List::new( + mmio_base, + registers.capability.hccparams1.read_volatile(), + Mapper, + ) + }; + + if let Some(mut list) = extended_capabilities { + for item in list.into_iter() { + qemu_println!("{:?}", item); + } + } let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); From ee69a5f1067e3a1908c8b346dd675e9dec1b3d36 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 4 Dec 2023 12:12:10 +0900 Subject: [PATCH 018/115] Singleton --- test/Cargo.toml | 2 ++ test/src/main.rs | 38 +++----------------------------------- test/src/mapper.rs | 12 ++++++++++++ test/src/registers.rs | 38 ++++++++++++++++++++++++++++++++++++++ test/src/xhc.rs | 1 + 5 files changed, 56 insertions(+), 35 deletions(-) create mode 100644 test/src/mapper.rs create mode 100644 test/src/registers.rs create mode 100644 test/src/xhc.rs diff --git a/test/Cargo.toml b/test/Cargo.toml index c188b38f..d72ccbb1 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -5,8 +5,10 @@ edition = "2021" [dependencies] bit_field = "0.10.2" +conquer-once = { version = "0.4.0", default-features = false } qemu-exit = "3.0.2" qemu_print = { version = "0.1.0", features = ["stable"], default-features = false } +spinning_top = "0.3.0" uefi = "0.26.0" x86_64 = { version = "0.14.11", default-features = false } xhci = { version = "0.9.2", path = ".." } diff --git a/test/src/main.rs b/test/src/main.rs index b365e5c8..a14e6643 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,51 +1,19 @@ #![no_std] #![no_main] +mod mapper; mod pci; +mod registers; -use core::num::NonZeroUsize; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; -use xhci::extended_capabilities; - -#[derive(Clone, Debug)] -struct Mapper; -impl xhci::accessor::Mapper for Mapper { - // UEFI sets up the identity mapping, so we don't need to do anything here. - unsafe fn map(&mut self, physical_address: usize, _: usize) -> NonZeroUsize { - NonZeroUsize::new(physical_address).expect("physical_address is zero") - } - - fn unmap(&mut self, _virtual_address: usize, _size: usize) {} -} #[uefi::entry] fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { let (_, _memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); - let xhc_config_space = pci::iter_xhc().next().expect("xHC not found"); - - let mmio_low = xhc_config_space.base_address_register(0); - let mmio_high = xhc_config_space.base_address_register(1); - - let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; - - let registers = unsafe { xhci::Registers::new(mmio_base, Mapper) }; - - let extended_capabilities = unsafe { - extended_capabilities::List::new( - mmio_base, - registers.capability.hccparams1.read_volatile(), - Mapper, - ) - }; - - if let Some(mut list) = extended_capabilities { - for item in list.into_iter() { - qemu_println!("{:?}", item); - } - } + registers::init(); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/mapper.rs b/test/src/mapper.rs new file mode 100644 index 00000000..b1a10014 --- /dev/null +++ b/test/src/mapper.rs @@ -0,0 +1,12 @@ +use core::num::NonZeroUsize; + +#[derive(Clone, Copy, Debug)] +pub struct Mapper; +impl xhci::accessor::Mapper for Mapper { + // UEFI sets up the identity mapping, so we don't need to do anything here. + unsafe fn map(&mut self, physical_address: usize, _: usize) -> NonZeroUsize { + NonZeroUsize::new(physical_address).expect("physical_address is zero") + } + + fn unmap(&mut self, _virtual_address: usize, _size: usize) {} +} diff --git a/test/src/registers.rs b/test/src/registers.rs new file mode 100644 index 00000000..3376364b --- /dev/null +++ b/test/src/registers.rs @@ -0,0 +1,38 @@ +use crate::mapper::Mapper; +use conquer_once::spin::OnceCell; +use qemu_print::qemu_println; +use spinning_top::Spinlock; + +static REGISTERS: OnceCell>> = OnceCell::uninit(); + +pub fn init() { + qemu_println!("Initializing registers..."); + + let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); + + let mmio_low = xhc_config_space.base_address_register(0); + let mmio_high = xhc_config_space.base_address_register(1); + + let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; + + let registers = unsafe { xhci::Registers::new(mmio_base, Mapper) }; + + REGISTERS.init_once(|| Spinlock::new(registers)); + + qemu_println!("Done."); +} + +/// To reduce the risk of deadlock caused by long-held register locks, the +/// approach involves minimizing the lock duration by receiving a closure +/// instead of returning the lock. +pub fn handle(f: T) -> U +where + T: FnOnce(&mut xhci::Registers) -> U, +{ + let mut r = REGISTERS + .try_get() + .expect("Registers not initialized") + .lock(); + + f(&mut r) +} diff --git a/test/src/xhc.rs b/test/src/xhc.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/src/xhc.rs @@ -0,0 +1 @@ + From fc2ae1f25946802d88c84928106933dfa7e93a89 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 10 Dec 2023 12:09:53 +0900 Subject: [PATCH 019/115] Workspace --- Cargo.toml | 21 +++---------------- lib/Cargo.toml | 18 ++++++++++++++++ {src => lib/src}/context/macros.rs | 0 {src => lib/src}/context/mod.rs | 0 .../src}/extended_capabilities/debug.rs | 0 .../hci_extended_power_management.rs | 0 {src => lib/src}/extended_capabilities/mod.rs | 0 .../usb_legacy_support_capability.rs | 0 .../xhci_extended_message_interrupt.rs | 0 .../xhci_local_memory.rs | 0 .../xhci_message_interrupt.rs | 0 .../xhci_supported_protocol.rs | 0 {src => lib/src}/lib.rs | 0 {src => lib/src}/macros.rs | 0 {src => lib/src}/registers/capability.rs | 0 {src => lib/src}/registers/doorbell.rs | 0 {src => lib/src}/registers/mod.rs | 0 {src => lib/src}/registers/operational.rs | 0 {src => lib/src}/registers/runtime.rs | 0 {src => lib/src}/ring/mod.rs | 0 {src => lib/src}/ring/trb/command.rs | 0 {src => lib/src}/ring/trb/event.rs | 0 {src => lib/src}/ring/trb/mod.rs | 0 {src => lib/src}/ring/trb/transfer.rs | 0 test/Cargo.toml | 2 +- test/Makefile | 2 +- 26 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 lib/Cargo.toml rename {src => lib/src}/context/macros.rs (100%) rename {src => lib/src}/context/mod.rs (100%) rename {src => lib/src}/extended_capabilities/debug.rs (100%) rename {src => lib/src}/extended_capabilities/hci_extended_power_management.rs (100%) rename {src => lib/src}/extended_capabilities/mod.rs (100%) rename {src => lib/src}/extended_capabilities/usb_legacy_support_capability.rs (100%) rename {src => lib/src}/extended_capabilities/xhci_extended_message_interrupt.rs (100%) rename {src => lib/src}/extended_capabilities/xhci_local_memory.rs (100%) rename {src => lib/src}/extended_capabilities/xhci_message_interrupt.rs (100%) rename {src => lib/src}/extended_capabilities/xhci_supported_protocol.rs (100%) rename {src => lib/src}/lib.rs (100%) rename {src => lib/src}/macros.rs (100%) rename {src => lib/src}/registers/capability.rs (100%) rename {src => lib/src}/registers/doorbell.rs (100%) rename {src => lib/src}/registers/mod.rs (100%) rename {src => lib/src}/registers/operational.rs (100%) rename {src => lib/src}/registers/runtime.rs (100%) rename {src => lib/src}/ring/mod.rs (100%) rename {src => lib/src}/ring/trb/command.rs (100%) rename {src => lib/src}/ring/trb/event.rs (100%) rename {src => lib/src}/ring/trb/mod.rs (100%) rename {src => lib/src}/ring/trb/transfer.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index ae6888c7..36e80599 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,3 @@ -[package] -name = "xhci" -version = "0.9.2" -authors = ["Hiroki Tokunaga "] -edition = "2021" -license = "MIT OR Apache-2.0" -description = "A library to handle xHCI" -repository = "https://github.com/rust-osdev/xhci" -readme = "README.md" -categories = ["no-std", "os"] -keywords = ["no_std", "OS"] - -[dependencies] -accessor = "0.3.0" -bit_field = "0.10.1" -num-derive = { version = "0.3.3", default-features = false } -num-traits = { version = "0.2.14", default-features = false } -paste = "1.0.4" +[workspace] +members = ["lib", "test"] +resolver = "2" diff --git a/lib/Cargo.toml b/lib/Cargo.toml new file mode 100644 index 00000000..ae6888c7 --- /dev/null +++ b/lib/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "xhci" +version = "0.9.2" +authors = ["Hiroki Tokunaga "] +edition = "2021" +license = "MIT OR Apache-2.0" +description = "A library to handle xHCI" +repository = "https://github.com/rust-osdev/xhci" +readme = "README.md" +categories = ["no-std", "os"] +keywords = ["no_std", "OS"] + +[dependencies] +accessor = "0.3.0" +bit_field = "0.10.1" +num-derive = { version = "0.3.3", default-features = false } +num-traits = { version = "0.2.14", default-features = false } +paste = "1.0.4" diff --git a/src/context/macros.rs b/lib/src/context/macros.rs similarity index 100% rename from src/context/macros.rs rename to lib/src/context/macros.rs diff --git a/src/context/mod.rs b/lib/src/context/mod.rs similarity index 100% rename from src/context/mod.rs rename to lib/src/context/mod.rs diff --git a/src/extended_capabilities/debug.rs b/lib/src/extended_capabilities/debug.rs similarity index 100% rename from src/extended_capabilities/debug.rs rename to lib/src/extended_capabilities/debug.rs diff --git a/src/extended_capabilities/hci_extended_power_management.rs b/lib/src/extended_capabilities/hci_extended_power_management.rs similarity index 100% rename from src/extended_capabilities/hci_extended_power_management.rs rename to lib/src/extended_capabilities/hci_extended_power_management.rs diff --git a/src/extended_capabilities/mod.rs b/lib/src/extended_capabilities/mod.rs similarity index 100% rename from src/extended_capabilities/mod.rs rename to lib/src/extended_capabilities/mod.rs diff --git a/src/extended_capabilities/usb_legacy_support_capability.rs b/lib/src/extended_capabilities/usb_legacy_support_capability.rs similarity index 100% rename from src/extended_capabilities/usb_legacy_support_capability.rs rename to lib/src/extended_capabilities/usb_legacy_support_capability.rs diff --git a/src/extended_capabilities/xhci_extended_message_interrupt.rs b/lib/src/extended_capabilities/xhci_extended_message_interrupt.rs similarity index 100% rename from src/extended_capabilities/xhci_extended_message_interrupt.rs rename to lib/src/extended_capabilities/xhci_extended_message_interrupt.rs diff --git a/src/extended_capabilities/xhci_local_memory.rs b/lib/src/extended_capabilities/xhci_local_memory.rs similarity index 100% rename from src/extended_capabilities/xhci_local_memory.rs rename to lib/src/extended_capabilities/xhci_local_memory.rs diff --git a/src/extended_capabilities/xhci_message_interrupt.rs b/lib/src/extended_capabilities/xhci_message_interrupt.rs similarity index 100% rename from src/extended_capabilities/xhci_message_interrupt.rs rename to lib/src/extended_capabilities/xhci_message_interrupt.rs diff --git a/src/extended_capabilities/xhci_supported_protocol.rs b/lib/src/extended_capabilities/xhci_supported_protocol.rs similarity index 100% rename from src/extended_capabilities/xhci_supported_protocol.rs rename to lib/src/extended_capabilities/xhci_supported_protocol.rs diff --git a/src/lib.rs b/lib/src/lib.rs similarity index 100% rename from src/lib.rs rename to lib/src/lib.rs diff --git a/src/macros.rs b/lib/src/macros.rs similarity index 100% rename from src/macros.rs rename to lib/src/macros.rs diff --git a/src/registers/capability.rs b/lib/src/registers/capability.rs similarity index 100% rename from src/registers/capability.rs rename to lib/src/registers/capability.rs diff --git a/src/registers/doorbell.rs b/lib/src/registers/doorbell.rs similarity index 100% rename from src/registers/doorbell.rs rename to lib/src/registers/doorbell.rs diff --git a/src/registers/mod.rs b/lib/src/registers/mod.rs similarity index 100% rename from src/registers/mod.rs rename to lib/src/registers/mod.rs diff --git a/src/registers/operational.rs b/lib/src/registers/operational.rs similarity index 100% rename from src/registers/operational.rs rename to lib/src/registers/operational.rs diff --git a/src/registers/runtime.rs b/lib/src/registers/runtime.rs similarity index 100% rename from src/registers/runtime.rs rename to lib/src/registers/runtime.rs diff --git a/src/ring/mod.rs b/lib/src/ring/mod.rs similarity index 100% rename from src/ring/mod.rs rename to lib/src/ring/mod.rs diff --git a/src/ring/trb/command.rs b/lib/src/ring/trb/command.rs similarity index 100% rename from src/ring/trb/command.rs rename to lib/src/ring/trb/command.rs diff --git a/src/ring/trb/event.rs b/lib/src/ring/trb/event.rs similarity index 100% rename from src/ring/trb/event.rs rename to lib/src/ring/trb/event.rs diff --git a/src/ring/trb/mod.rs b/lib/src/ring/trb/mod.rs similarity index 100% rename from src/ring/trb/mod.rs rename to lib/src/ring/trb/mod.rs diff --git a/src/ring/trb/transfer.rs b/lib/src/ring/trb/transfer.rs similarity index 100% rename from src/ring/trb/transfer.rs rename to lib/src/ring/trb/transfer.rs diff --git a/test/Cargo.toml b/test/Cargo.toml index d72ccbb1..a06560d5 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -11,4 +11,4 @@ qemu_print = { version = "0.1.0", features = ["stable"], default-features = fals spinning_top = "0.3.0" uefi = "0.26.0" x86_64 = { version = "0.14.11", default-features = false } -xhci = { version = "0.9.2", path = ".." } +xhci = { version = "0.9.2", path = "../lib" } diff --git a/test/Makefile b/test/Makefile index 7db1fc41..afa75225 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,5 +1,5 @@ IMG = build/os.img -EFI = target/x86_64-unknown-uefi/debug/xhci-test.efi +EFI = ../target/x86_64-unknown-uefi/debug/xhci-test.efi .PHONY: test clean From ad7fa526d2760a07649ef6033317da68a493301f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 10 Dec 2023 12:28:51 +0900 Subject: [PATCH 020/115] Initialize xHC --- test/src/main.rs | 3 ++ test/src/xhc.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/test/src/main.rs b/test/src/main.rs index a14e6643..6ad18b11 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -4,6 +4,7 @@ mod mapper; mod pci; mod registers; +mod xhc; use qemu_exit::QEMUExit; use qemu_print::qemu_println; @@ -15,6 +16,8 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> registers::init(); + xhc::init(); + let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 8b137891..98c6aba7 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1 +1,90 @@ +use crate::registers; +use qemu_print::qemu_println; +pub fn init() { + qemu_println!("Initializing xHC..."); + + stop_and_reset(); + set_num_of_enabled_slots(); + + qemu_println!("xHC is initialized."); +} + +pub fn ensure_no_error_occurs() { + registers::handle(|r| { + let s = r.operational.usbsts.read_volatile(); + + assert!(!s.hc_halted(), "HC is halted."); + assert!( + !s.host_system_error(), + "An error occured on the host system." + ); + assert!(!s.host_controller_error(), "An error occured on the xHC."); + }); +} + +fn stop_and_reset() { + stop(); + wait_until_halt(); + reset(); +} + +fn stop() { + registers::handle(|r| { + r.operational.usbcmd.update_volatile(|u| { + u.clear_run_stop(); + }); + }); +} + +fn wait_until_halt() { + registers::handle(|r| while !r.operational.usbsts.read_volatile().hc_halted() {}); +} + +fn reset() { + start_resetting(); + wait_until_reset_completed(); + wait_until_ready(); +} + +fn start_resetting() { + registers::handle(|r| { + r.operational.usbcmd.update_volatile(|u| { + u.set_host_controller_reset(); + }); + }); +} + +fn wait_until_reset_completed() { + registers::handle( + |r| { + while r.operational.usbcmd.read_volatile().host_controller_reset() {} + }, + ); +} + +fn wait_until_ready() { + registers::handle( + |r| { + while r.operational.usbsts.read_volatile().controller_not_ready() {} + }, + ); +} + +fn set_num_of_enabled_slots() { + let n = num_of_device_slots(); + registers::handle(|r| { + r.operational.config.update_volatile(|c| { + c.set_max_device_slots_enabled(n); + }); + }); +} + +fn num_of_device_slots() -> u8 { + registers::handle(|r| { + r.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() + }) +} From f62994fe8463b1c9a0c072bbba32dc83ae26ee25 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 10 Dec 2023 15:36:22 +0900 Subject: [PATCH 021/115] Allocator --- test/Cargo.toml | 1 + test/src/allocator.rs | 33 +++++++++++++++++++++++++++++++++ test/src/main.rs | 6 +++++- 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 test/src/allocator.rs diff --git a/test/Cargo.toml b/test/Cargo.toml index a06560d5..3c6a1cb1 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] bit_field = "0.10.2" conquer-once = { version = "0.4.0", default-features = false } +linked_list_allocator = "0.10.5" qemu-exit = "3.0.2" qemu_print = { version = "0.1.0", features = ["stable"], default-features = false } spinning_top = "0.3.0" diff --git a/test/src/allocator.rs b/test/src/allocator.rs new file mode 100644 index 00000000..ae83f327 --- /dev/null +++ b/test/src/allocator.rs @@ -0,0 +1,33 @@ +use alloc::collections::LinkedList; +use core::alloc::{GlobalAlloc, Layout}; +use linked_list_allocator::LockedHeap; +use uefi::table::boot; + +#[global_allocator] +static mut ALLOCATOR: LockedHeap = LockedHeap::empty(); + +pub fn init(memory_map: boot::MemoryMap) { + let largest_chunk = find_largest_conventional_memory_chunk(memory_map); + + let heap_start = largest_chunk.phys_start; + let heap_end = heap_start + largest_chunk.page_count * 4096; + let heap_size = heap_end - heap_start; + + unsafe { + ALLOCATOR + .lock() + .init(heap_start as *mut _, heap_size.try_into().unwrap()); + } +} + +fn find_largest_conventional_memory_chunk(memory_map: boot::MemoryMap) -> boot::MemoryDescriptor { + // Only EfiConventionalMemory is used because dealing with additional memory + // types involves unnecessary complexity, given the presence of stack space + // in EfiBootServicesData (confirmed by manual testing) and UEFI binaries in + // EfiLoaderData (as specified in UEFI version 2.10, Table 7.6.) + *memory_map + .entries() + .filter(|x| x.ty == boot::MemoryType::CONVENTIONAL) + .max_by_key(|x| x.page_count) + .expect("No conventional memory found") +} diff --git a/test/src/main.rs b/test/src/main.rs index 6ad18b11..deb76d61 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +extern crate alloc; + +mod allocator; mod mapper; mod pci; mod registers; @@ -12,7 +15,8 @@ use uefi::table::boot::MemoryType; #[uefi::entry] fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { - let (_, _memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); + let (_, memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); + allocator::init(memory_map); registers::init(); From fbb855d9afbbf13c8c6490f346f088f3655bf738 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 11 Dec 2023 10:57:34 +0900 Subject: [PATCH 022/115] Doc --- test/src/allocator.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/src/allocator.rs b/test/src/allocator.rs index ae83f327..2545a4ac 100644 --- a/test/src/allocator.rs +++ b/test/src/allocator.rs @@ -21,9 +21,10 @@ pub fn init(memory_map: boot::MemoryMap) { } fn find_largest_conventional_memory_chunk(memory_map: boot::MemoryMap) -> boot::MemoryDescriptor { - // Only EfiConventionalMemory is used because dealing with additional memory - // types involves unnecessary complexity, given the presence of stack space - // in EfiBootServicesData (confirmed by manual testing) and UEFI binaries in + // Only EfiConventionalMemory which is usable both before and after exiting + // the boot service is used because dealing with additional memory types + // involves unnecessary complexity, given the presence of stack space in + // EfiBootServicesData (confirmed by manual testing) and UEFI binaries in // EfiLoaderData (as specified in UEFI version 2.10, Table 7.6.) *memory_map .entries() From c52fc4d86f5b8a49bbe5290345c00f7099e62391 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 11 Dec 2023 11:37:50 +0900 Subject: [PATCH 023/115] Allocate rings --- test/src/event_ring.rs | 79 ++++++++++++++++++++++++++++++++++++++++++ test/src/main.rs | 3 ++ 2 files changed, 82 insertions(+) create mode 100644 test/src/event_ring.rs diff --git a/test/src/event_ring.rs b/test/src/event_ring.rs new file mode 100644 index 00000000..973caccd --- /dev/null +++ b/test/src/event_ring.rs @@ -0,0 +1,79 @@ +use crate::registers; +use alloc::{boxed::Box, vec, vec::Vec}; +use conquer_once::spin::OnceCell; +use qemu_print::qemu_println; +use spinning_top::Spinlock; + +static EVENT_RING_SEGMENT_TABLE: OnceCell> = OnceCell::uninit(); +static EVENT_RINGS: OnceCell> = OnceCell::uninit(); + +pub fn init() { + allocate_event_ring_segment_table(); + + allocate_event_rings(); +} + +fn allocate_event_ring_segment_table() { + EVENT_RING_SEGMENT_TABLE + .try_init_once(|| Spinlock::new(EventRingSegmentTable::new())) + .expect("Event ring segment table already initialized"); + + qemu_println!("Event ring segment table is initialized"); +} + +fn allocate_event_rings() { + EVENT_RINGS + .try_init_once(|| Spinlock::new(EventRingCollection::new())) + .expect("Event rings already initialized"); + + qemu_println!("Event rings are initialized"); +} + +struct EventRingSegmentTable(Vec); +impl EventRingSegmentTable { + fn new() -> Self { + Self(vec![ + EventRingSegmentTableEntry::null(); + number_of_rings().into() + ]) + } +} + +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +struct EventRingSegmentTableEntry { + base_address: u64, + segment_size: u64, +} +impl EventRingSegmentTableEntry { + fn null() -> Self { + Self { + base_address: 0, + segment_size: 0, + } + } +} + +struct EventRingCollection(Vec); +impl EventRingCollection { + fn new() -> Self { + Self(vec![EventRing::new(); number_of_rings().into()]) + } +} + +#[derive(Clone, Debug)] +struct EventRing(Box<[[u32; 4]; 256]>); +impl EventRing { + fn new() -> Self { + Self(Box::new([[0; 4]; 256])) + } +} + +fn number_of_rings() -> u16 { + registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .event_ring_segment_table_max() + }) +} diff --git a/test/src/main.rs b/test/src/main.rs index deb76d61..0c947af2 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -4,6 +4,7 @@ extern crate alloc; mod allocator; +mod event_ring; mod mapper; mod pci; mod registers; @@ -22,6 +23,8 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::init(); + event_ring::init(); + let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } From eb6c038628f949e43487dbc242c5b8bbe0e4415f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 19:16:50 +0900 Subject: [PATCH 024/115] Event rings --- test/src/event.rs | 134 +++++++++++++++++++++++++++++++++++++++++ test/src/event_ring.rs | 79 ------------------------ test/src/main.rs | 4 +- 3 files changed, 136 insertions(+), 81 deletions(-) create mode 100644 test/src/event.rs delete mode 100644 test/src/event_ring.rs diff --git a/test/src/event.rs b/test/src/event.rs new file mode 100644 index 00000000..b7810fd4 --- /dev/null +++ b/test/src/event.rs @@ -0,0 +1,134 @@ +use crate::registers; +use alloc::{boxed::Box, vec, vec::Vec}; +use conquer_once::spin::OnceCell; +use qemu_print::qemu_println; +use spinning_top::Spinlock; +use xhci::ring::trb; + +static EVENT_HANDLER: OnceCell> = OnceCell::uninit(); + +// Just an arbitrary number. +const NUM_OF_TRBS_IN_RING: usize = 10; + +pub fn init() { + let handler = EventHandler::new(); + + EVENT_HANDLER + .try_init_once(|| Spinlock::new(handler)) + .expect("EventHandler::new() called more than once"); + + EVENT_HANDLER + .get() + .unwrap_or_else(|| unreachable!("Should be initialized")) + .lock() + .init(); + + qemu_println!("Event rings and segment tables are initialized"); +} + +struct EventHandler { + segment_table: Vec, + rings: Vec, + + dequeue_ptr_segment: u64, + dequeue_ptr_ring: u64, + + cycle_bit: bool, +} +impl EventHandler { + fn new() -> Self { + Self { + segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings().into()], + rings: vec![EventRing::new(); number_of_rings().into()], + + dequeue_ptr_segment: 0, + dequeue_ptr_ring: 0, + + cycle_bit: true, + } + } + + fn init(&mut self) { + self.register_dequeue_pointer(); + + self.write_rings_addresses_in_table(); + self.register_table_size(); + self.enable_event_ring(); + } + + fn register_dequeue_pointer(&self) { + registers::handle(|r| { + r.interrupter_register_set + .interrupter_mut(0) + .erdp + .update_volatile(|erdp| erdp.set_event_ring_dequeue_pointer(self.next_trb_addr())) + }) + } + + fn write_rings_addresses_in_table(&mut self) { + let mut segment_table = self.segment_table.clone(); + + for (i, ring) in self.rings.iter().enumerate() { + segment_table[i].base_addr = ring as *const _ as u64; + segment_table[i].segment_size = NUM_OF_TRBS_IN_RING as _; + } + } + + fn register_table_size(&self) { + registers::handle(|r| { + r.interrupter_register_set + .interrupter_mut(0) + .erstsz + .update_volatile(|erstsz| { + erstsz.set(self.segment_table.len() as u16); + }) + }) + } + + fn enable_event_ring(&self) { + registers::handle(|r| { + r.interrupter_register_set + .interrupter_mut(0) + .erstba + .update_volatile(|erstba| erstba.set(self.segment_table.as_ptr() as u64)) + }) + } + + fn next_trb_addr(&self) -> u64 { + self.segment_table[self.dequeue_ptr_segment as usize].base_addr + + self.dequeue_ptr_ring as u64 * trb::BYTES as u64 + } +} + +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +struct EventRingSegmentTableEntry { + base_addr: u64, + segment_size: u64, +} +impl EventRingSegmentTableEntry { + fn null() -> Self { + Self { + base_addr: 0, + segment_size: 0, + } + } +} + +#[repr(C, align(64))] +#[derive(Clone, Copy, Debug)] +struct EventRing([[u32; 4]; NUM_OF_TRBS_IN_RING]); +impl EventRing { + fn new() -> Self { + Self([[0; 4]; NUM_OF_TRBS_IN_RING]) + } +} + +fn number_of_rings() -> u16 { + registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .event_ring_segment_table_max() + }) +} diff --git a/test/src/event_ring.rs b/test/src/event_ring.rs deleted file mode 100644 index 973caccd..00000000 --- a/test/src/event_ring.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::registers; -use alloc::{boxed::Box, vec, vec::Vec}; -use conquer_once::spin::OnceCell; -use qemu_print::qemu_println; -use spinning_top::Spinlock; - -static EVENT_RING_SEGMENT_TABLE: OnceCell> = OnceCell::uninit(); -static EVENT_RINGS: OnceCell> = OnceCell::uninit(); - -pub fn init() { - allocate_event_ring_segment_table(); - - allocate_event_rings(); -} - -fn allocate_event_ring_segment_table() { - EVENT_RING_SEGMENT_TABLE - .try_init_once(|| Spinlock::new(EventRingSegmentTable::new())) - .expect("Event ring segment table already initialized"); - - qemu_println!("Event ring segment table is initialized"); -} - -fn allocate_event_rings() { - EVENT_RINGS - .try_init_once(|| Spinlock::new(EventRingCollection::new())) - .expect("Event rings already initialized"); - - qemu_println!("Event rings are initialized"); -} - -struct EventRingSegmentTable(Vec); -impl EventRingSegmentTable { - fn new() -> Self { - Self(vec![ - EventRingSegmentTableEntry::null(); - number_of_rings().into() - ]) - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -struct EventRingSegmentTableEntry { - base_address: u64, - segment_size: u64, -} -impl EventRingSegmentTableEntry { - fn null() -> Self { - Self { - base_address: 0, - segment_size: 0, - } - } -} - -struct EventRingCollection(Vec); -impl EventRingCollection { - fn new() -> Self { - Self(vec![EventRing::new(); number_of_rings().into()]) - } -} - -#[derive(Clone, Debug)] -struct EventRing(Box<[[u32; 4]; 256]>); -impl EventRing { - fn new() -> Self { - Self(Box::new([[0; 4]; 256])) - } -} - -fn number_of_rings() -> u16 { - registers::handle(|r| { - r.capability - .hcsparams2 - .read_volatile() - .event_ring_segment_table_max() - }) -} diff --git a/test/src/main.rs b/test/src/main.rs index 0c947af2..0b75165a 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -4,7 +4,7 @@ extern crate alloc; mod allocator; -mod event_ring; +mod event; mod mapper; mod pci; mod registers; @@ -23,7 +23,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::init(); - event_ring::init(); + event::init(); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); From d4243036d59f76043dcdd2321b4e48d5484a3bbf Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 19:24:58 +0900 Subject: [PATCH 025/115] Minimum is defined --- test/src/event.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index b7810fd4..08a8fd13 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -7,8 +7,7 @@ use xhci::ring::trb; static EVENT_HANDLER: OnceCell> = OnceCell::uninit(); -// Just an arbitrary number. -const NUM_OF_TRBS_IN_RING: usize = 10; +const NUM_OF_TRBS_IN_RING: usize = 16; pub fn init() { let handler = EventHandler::new(); From 54e7363d6afd0ea411d7b1e32722d94aad74657d Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 19:35:47 +0900 Subject: [PATCH 026/115] Command ring --- test/src/command_ring.rs | 59 ++++++++++++++++++++++++++++++++++++++++ test/src/main.rs | 2 ++ 2 files changed, 61 insertions(+) create mode 100644 test/src/command_ring.rs diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs new file mode 100644 index 00000000..c16eb11d --- /dev/null +++ b/test/src/command_ring.rs @@ -0,0 +1,59 @@ +use crate::registers; +use alloc::boxed::Box; +use conquer_once::spin::OnceCell; +use qemu_print::qemu_println; +use spinning_top::Spinlock; + +static COMMAND_RING_CONTROLLER: OnceCell> = OnceCell::uninit(); + +const NUM_OF_TRBS_IN_RING: usize = 10; + +pub fn init() { + let controller = CommandRingController::new(); + + COMMAND_RING_CONTROLLER + .try_init_once(|| Spinlock::new(controller)) + .expect("CommandRingController::new() called more than once"); + + COMMAND_RING_CONTROLLER + .get() + .unwrap_or_else(|| unreachable!("Should be initialized")) + .lock() + .init(); + + qemu_println!("Command ring is initialized"); +} + +struct CommandRingController { + ring: Box, + + enqueue_ptr: usize, + cycle_bit: bool, +} +impl CommandRingController { + fn new() -> Self { + Self { + ring: Box::new(CommandRing::new()), + + enqueue_ptr: 0, + cycle_bit: true, + } + } + + fn init(&mut self) { + registers::handle(|r| { + r.operational.crcr.update_volatile(|crcr| { + crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); + crcr.set_ring_cycle_state(); + }); + }) + } +} + +#[repr(C, align(64))] +struct CommandRing([[u32; 4]; NUM_OF_TRBS_IN_RING]); +impl CommandRing { + fn new() -> Self { + Self([[0; 4]; NUM_OF_TRBS_IN_RING]) + } +} diff --git a/test/src/main.rs b/test/src/main.rs index 0b75165a..eee8dd8c 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -4,6 +4,7 @@ extern crate alloc; mod allocator; +mod command_ring; mod event; mod mapper; mod pci; @@ -24,6 +25,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::init(); event::init(); + command_ring::init(); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); From f1452054574552275706de95a969669d34e1f326 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 19:44:55 +0900 Subject: [PATCH 027/115] DCBAA --- test/src/dcbaa.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++ test/src/main.rs | 2 ++ 2 files changed, 54 insertions(+) create mode 100644 test/src/dcbaa.rs diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs new file mode 100644 index 00000000..66656bff --- /dev/null +++ b/test/src/dcbaa.rs @@ -0,0 +1,52 @@ +use crate::registers; +use alloc::vec; +use alloc::vec::Vec; +use conquer_once::spin::OnceCell; +use qemu_print::qemu_println; +use spinning_top::Spinlock; + +static DCBAA: OnceCell> = OnceCell::uninit(); + +pub fn init() { + DCBAA + .try_init_once(|| Spinlock::new(DeviceContextBaseAddressArray::new())) + .expect("DeviceContextBaseAddressArray::new() called more than once"); + + DCBAA + .get() + .unwrap_or_else(|| unreachable!("Should be initialized")) + .lock() + .init(); + + qemu_println!("Device Context Base Address Array is initialized"); +} + +struct DeviceContextBaseAddressArray(Vec); +impl DeviceContextBaseAddressArray { + fn new() -> Self { + Self(vec![0; number_of_slots()]) + } + + fn init(&mut self) { + self.register_address_with_register(); + } + + fn register_address_with_register(&self) { + registers::handle(|r| { + r.operational + .dcbaap + .update_volatile(|dcbaap| dcbaap.set(self.0.as_ptr() as u64)); + }); + } +} + +fn number_of_slots() -> usize { + registers::handle(|r| { + r.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() + + 1 + }) + .into() +} diff --git a/test/src/main.rs b/test/src/main.rs index eee8dd8c..d503f119 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -5,6 +5,7 @@ extern crate alloc; mod allocator; mod command_ring; +mod dcbaa; mod event; mod mapper; mod pci; @@ -26,6 +27,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> event::init(); command_ring::init(); + dcbaa::init(); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); From 7db9ad8e60e568354d9918203cff0b47ab101cf5 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 23:26:07 +0900 Subject: [PATCH 028/115] Scratchpad --- test/src/dcbaa.rs | 13 +++++++++++-- test/src/main.rs | 2 ++ test/src/scratchpat.rs | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 test/src/scratchpat.rs diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs index 66656bff..1e6edc4d 100644 --- a/test/src/dcbaa.rs +++ b/test/src/dcbaa.rs @@ -21,10 +21,10 @@ pub fn init() { qemu_println!("Device Context Base Address Array is initialized"); } -struct DeviceContextBaseAddressArray(Vec); +struct DeviceContextBaseAddressArray(Vec); impl DeviceContextBaseAddressArray { fn new() -> Self { - Self(vec![0; number_of_slots()]) + Self(vec![RawDCBAA::new(); number_of_slots()]) } fn init(&mut self) { @@ -40,6 +40,15 @@ impl DeviceContextBaseAddressArray { } } +#[repr(C, align(64))] +#[derive(Clone, Copy)] +struct RawDCBAA(u64); +impl RawDCBAA { + fn new() -> Self { + Self(0) + } +} + fn number_of_slots() -> usize { registers::handle(|r| { r.capability diff --git a/test/src/main.rs b/test/src/main.rs index d503f119..880d4826 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -10,6 +10,7 @@ mod event; mod mapper; mod pci; mod registers; +mod scratchpat; mod xhc; use qemu_exit::QEMUExit; @@ -28,6 +29,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> event::init(); command_ring::init(); dcbaa::init(); + scratchpat::init(); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/scratchpat.rs b/test/src/scratchpat.rs new file mode 100644 index 00000000..fb0ca3c2 --- /dev/null +++ b/test/src/scratchpat.rs @@ -0,0 +1,14 @@ +use crate::registers; + +pub fn init() { + let num_of_buffers = registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .max_scratchpad_buffers() + }); + + if num_of_buffers > 0 { + todo!("Implement scratchpad buffer initialization"); + } +} From cbdfb929046e32b9e61784407e11593416cab09a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 23:30:01 +0900 Subject: [PATCH 029/115] Run --- test/src/main.rs | 3 +++ test/src/xhc.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/test/src/main.rs b/test/src/main.rs index 880d4826..79713e83 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -31,6 +31,9 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> dcbaa::init(); scratchpat::init(); + xhc::run(); + xhc::ensure_no_error_occurs(); + let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 98c6aba7..95e1d545 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -10,6 +10,18 @@ pub fn init() { qemu_println!("xHC is initialized."); } +pub fn run() { + registers::handle(|r| { + let o = &mut r.operational; + + o.usbcmd.update_volatile(|u| { + u.set_run_stop(); + }); + + while o.usbsts.read_volatile().hc_halted() {} + }); +} + pub fn ensure_no_error_occurs() { registers::handle(|r| { let s = r.operational.usbsts.read_volatile(); From cb143953294f43d71a97cb18fe8cd775a59f645a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 23:38:46 +0900 Subject: [PATCH 030/115] No static just a test --- test/src/registers.rs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/test/src/registers.rs b/test/src/registers.rs index 3376364b..849dc339 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -3,22 +3,9 @@ use conquer_once::spin::OnceCell; use qemu_print::qemu_println; use spinning_top::Spinlock; -static REGISTERS: OnceCell>> = OnceCell::uninit(); - pub fn init() { qemu_println!("Initializing registers..."); - let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); - - let mmio_low = xhc_config_space.base_address_register(0); - let mmio_high = xhc_config_space.base_address_register(1); - - let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; - - let registers = unsafe { xhci::Registers::new(mmio_base, Mapper) }; - - REGISTERS.init_once(|| Spinlock::new(registers)); - qemu_println!("Done."); } @@ -29,10 +16,18 @@ pub fn handle(f: T) -> U where T: FnOnce(&mut xhci::Registers) -> U, { - let mut r = REGISTERS - .try_get() - .expect("Registers not initialized") - .lock(); + let mut r = get_accessor(); f(&mut r) } + +fn get_accessor() -> xhci::Registers { + let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); + + let mmio_low = xhc_config_space.base_address_register(0); + let mmio_high = xhc_config_space.base_address_register(1); + + let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; + + unsafe { xhci::Registers::new(mmio_base, Mapper) } +} From 9c0bf6ef3e01beada5a36b30f9b33a1f7bb7823d Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 12 Dec 2023 23:53:28 +0900 Subject: [PATCH 031/115] No static register --- test/src/allocator.rs | 2 - test/src/command_ring.rs | 18 +++--- test/src/dcbaa.rs | 41 ++++++------- test/src/event.rs | 76 +++++++++++------------- test/src/main.rs | 16 ++--- test/src/registers.rs | 23 +------ test/src/scratchpat.rs | 15 +++-- test/src/xhc.rs | 125 ++++++++++++++++++--------------------- 8 files changed, 135 insertions(+), 181 deletions(-) diff --git a/test/src/allocator.rs b/test/src/allocator.rs index 2545a4ac..a3759b70 100644 --- a/test/src/allocator.rs +++ b/test/src/allocator.rs @@ -1,5 +1,3 @@ -use alloc::collections::LinkedList; -use core::alloc::{GlobalAlloc, Layout}; use linked_list_allocator::LockedHeap; use uefi::table::boot; diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index c16eb11d..3ef7ed65 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,4 +1,4 @@ -use crate::registers; +use crate::registers::Registers; use alloc::boxed::Box; use conquer_once::spin::OnceCell; use qemu_print::qemu_println; @@ -8,7 +8,7 @@ static COMMAND_RING_CONTROLLER: OnceCell> = Once const NUM_OF_TRBS_IN_RING: usize = 10; -pub fn init() { +pub fn init(regs: &mut Registers) { let controller = CommandRingController::new(); COMMAND_RING_CONTROLLER @@ -19,7 +19,7 @@ pub fn init() { .get() .unwrap_or_else(|| unreachable!("Should be initialized")) .lock() - .init(); + .init(regs); qemu_println!("Command ring is initialized"); } @@ -40,13 +40,11 @@ impl CommandRingController { } } - fn init(&mut self) { - registers::handle(|r| { - r.operational.crcr.update_volatile(|crcr| { - crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); - crcr.set_ring_cycle_state(); - }); - }) + fn init(&mut self, regs: &mut Registers) { + regs.operational.crcr.update_volatile(|crcr| { + crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); + crcr.set_ring_cycle_state(); + }); } } diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs index 1e6edc4d..119d142c 100644 --- a/test/src/dcbaa.rs +++ b/test/src/dcbaa.rs @@ -1,4 +1,4 @@ -use crate::registers; +use crate::registers::Registers; use alloc::vec; use alloc::vec::Vec; use conquer_once::spin::OnceCell; @@ -7,36 +7,34 @@ use spinning_top::Spinlock; static DCBAA: OnceCell> = OnceCell::uninit(); -pub fn init() { +pub fn init(regs: &mut Registers) { DCBAA - .try_init_once(|| Spinlock::new(DeviceContextBaseAddressArray::new())) + .try_init_once(|| Spinlock::new(DeviceContextBaseAddressArray::new(regs))) .expect("DeviceContextBaseAddressArray::new() called more than once"); DCBAA .get() .unwrap_or_else(|| unreachable!("Should be initialized")) .lock() - .init(); + .init(regs); qemu_println!("Device Context Base Address Array is initialized"); } struct DeviceContextBaseAddressArray(Vec); impl DeviceContextBaseAddressArray { - fn new() -> Self { - Self(vec![RawDCBAA::new(); number_of_slots()]) + fn new(regs: &Registers) -> Self { + Self(vec![RawDCBAA::new(); number_of_slots(regs)]) } - fn init(&mut self) { - self.register_address_with_register(); + fn init(&mut self, regs: &mut Registers) { + self.register_address_with_register(regs); } - fn register_address_with_register(&self) { - registers::handle(|r| { - r.operational - .dcbaap - .update_volatile(|dcbaap| dcbaap.set(self.0.as_ptr() as u64)); - }); + fn register_address_with_register(&self, regs: &mut Registers) { + regs.operational + .dcbaap + .update_volatile(|dcbaap| dcbaap.set(self.0.as_ptr() as u64)); } } @@ -49,13 +47,10 @@ impl RawDCBAA { } } -fn number_of_slots() -> usize { - registers::handle(|r| { - r.capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() - + 1 - }) - .into() +fn number_of_slots(regs: &Registers) -> usize { + regs.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() as usize + + 1_usize } diff --git a/test/src/event.rs b/test/src/event.rs index 08a8fd13..9901219d 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -1,5 +1,5 @@ -use crate::registers; -use alloc::{boxed::Box, vec, vec::Vec}; +use crate::registers::Registers; +use alloc::{vec, vec::Vec}; use conquer_once::spin::OnceCell; use qemu_print::qemu_println; use spinning_top::Spinlock; @@ -9,8 +9,8 @@ static EVENT_HANDLER: OnceCell> = OnceCell::uninit(); const NUM_OF_TRBS_IN_RING: usize = 16; -pub fn init() { - let handler = EventHandler::new(); +pub fn init(regs: &mut Registers) { + let handler = EventHandler::new(regs); EVENT_HANDLER .try_init_once(|| Spinlock::new(handler)) @@ -20,7 +20,7 @@ pub fn init() { .get() .unwrap_or_else(|| unreachable!("Should be initialized")) .lock() - .init(); + .init(regs); qemu_println!("Event rings and segment tables are initialized"); } @@ -35,10 +35,10 @@ struct EventHandler { cycle_bit: bool, } impl EventHandler { - fn new() -> Self { + fn new(regs: &Registers) -> Self { Self { - segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings().into()], - rings: vec![EventRing::new(); number_of_rings().into()], + segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings(regs).into()], + rings: vec![EventRing::new(); number_of_rings(regs).into()], dequeue_ptr_segment: 0, dequeue_ptr_ring: 0, @@ -47,21 +47,19 @@ impl EventHandler { } } - fn init(&mut self) { - self.register_dequeue_pointer(); + fn init(&mut self, regs: &mut Registers) { + self.register_dequeue_pointer(regs); self.write_rings_addresses_in_table(); - self.register_table_size(); - self.enable_event_ring(); + self.register_table_size(regs); + self.enable_event_ring(regs); } - fn register_dequeue_pointer(&self) { - registers::handle(|r| { - r.interrupter_register_set - .interrupter_mut(0) - .erdp - .update_volatile(|erdp| erdp.set_event_ring_dequeue_pointer(self.next_trb_addr())) - }) + fn register_dequeue_pointer(&self, regs: &mut Registers) { + regs.interrupter_register_set + .interrupter_mut(0) + .erdp + .update_volatile(|erdp| erdp.set_event_ring_dequeue_pointer(self.next_trb_addr())) } fn write_rings_addresses_in_table(&mut self) { @@ -73,24 +71,20 @@ impl EventHandler { } } - fn register_table_size(&self) { - registers::handle(|r| { - r.interrupter_register_set - .interrupter_mut(0) - .erstsz - .update_volatile(|erstsz| { - erstsz.set(self.segment_table.len() as u16); - }) - }) + fn register_table_size(&self, regs: &mut Registers) { + regs.interrupter_register_set + .interrupter_mut(0) + .erstsz + .update_volatile(|erstsz| { + erstsz.set(self.segment_table.len() as u16); + }) } - fn enable_event_ring(&self) { - registers::handle(|r| { - r.interrupter_register_set - .interrupter_mut(0) - .erstba - .update_volatile(|erstba| erstba.set(self.segment_table.as_ptr() as u64)) - }) + fn enable_event_ring(&self, regs: &mut Registers) { + regs.interrupter_register_set + .interrupter_mut(0) + .erstba + .update_volatile(|erstba| erstba.set(self.segment_table.as_ptr() as u64)) } fn next_trb_addr(&self) -> u64 { @@ -123,11 +117,9 @@ impl EventRing { } } -fn number_of_rings() -> u16 { - registers::handle(|r| { - r.capability - .hcsparams2 - .read_volatile() - .event_ring_segment_table_max() - }) +fn number_of_rings(regs: &Registers) -> u16 { + regs.capability + .hcsparams2 + .read_volatile() + .event_ring_segment_table_max() } diff --git a/test/src/main.rs b/test/src/main.rs index 79713e83..f11be293 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -22,17 +22,17 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let (_, memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); allocator::init(memory_map); - registers::init(); + let mut regs = registers::get_accessor(); - xhc::init(); + xhc::init(&mut regs); - event::init(); - command_ring::init(); - dcbaa::init(); - scratchpat::init(); + event::init(&mut regs); + command_ring::init(&mut regs); + dcbaa::init(&mut regs); + scratchpat::init(®s); - xhc::run(); - xhc::ensure_no_error_occurs(); + xhc::run(&mut regs); + xhc::ensure_no_error_occurs(®s); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/registers.rs b/test/src/registers.rs index 849dc339..202e88e4 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -1,27 +1,8 @@ use crate::mapper::Mapper; -use conquer_once::spin::OnceCell; -use qemu_print::qemu_println; -use spinning_top::Spinlock; -pub fn init() { - qemu_println!("Initializing registers..."); +pub type Registers = xhci::Registers; - qemu_println!("Done."); -} - -/// To reduce the risk of deadlock caused by long-held register locks, the -/// approach involves minimizing the lock duration by receiving a closure -/// instead of returning the lock. -pub fn handle(f: T) -> U -where - T: FnOnce(&mut xhci::Registers) -> U, -{ - let mut r = get_accessor(); - - f(&mut r) -} - -fn get_accessor() -> xhci::Registers { +pub fn get_accessor() -> Registers { let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); let mmio_low = xhc_config_space.base_address_register(0); diff --git a/test/src/scratchpat.rs b/test/src/scratchpat.rs index fb0ca3c2..0c14f1f4 100644 --- a/test/src/scratchpat.rs +++ b/test/src/scratchpat.rs @@ -1,12 +1,11 @@ -use crate::registers; +use crate::registers::Registers; -pub fn init() { - let num_of_buffers = registers::handle(|r| { - r.capability - .hcsparams2 - .read_volatile() - .max_scratchpad_buffers() - }); +pub fn init(regs: &Registers) { + let num_of_buffers = regs + .capability + .hcsparams2 + .read_volatile() + .max_scratchpad_buffers(); if num_of_buffers > 0 { todo!("Implement scratchpad buffer initialization"); diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 95e1d545..e26cd351 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,102 +1,93 @@ -use crate::registers; +use crate::registers::Registers; use qemu_print::qemu_println; -pub fn init() { +pub fn init(regs: &mut Registers) { qemu_println!("Initializing xHC..."); - stop_and_reset(); - set_num_of_enabled_slots(); + stop_and_reset(regs); + set_num_of_enabled_slots(regs); qemu_println!("xHC is initialized."); } -pub fn run() { - registers::handle(|r| { - let o = &mut r.operational; +pub fn run(regs: &mut Registers) { + let o = &mut regs.operational; - o.usbcmd.update_volatile(|u| { - u.set_run_stop(); - }); - - while o.usbsts.read_volatile().hc_halted() {} + o.usbcmd.update_volatile(|u| { + u.set_run_stop(); }); + + while o.usbsts.read_volatile().hc_halted() {} } -pub fn ensure_no_error_occurs() { - registers::handle(|r| { - let s = r.operational.usbsts.read_volatile(); +pub fn ensure_no_error_occurs(regs: &Registers) { + let s = regs.operational.usbsts.read_volatile(); - assert!(!s.hc_halted(), "HC is halted."); - assert!( - !s.host_system_error(), - "An error occured on the host system." - ); - assert!(!s.host_controller_error(), "An error occured on the xHC."); - }); + assert!(!s.hc_halted(), "HC is halted."); + assert!( + !s.host_system_error(), + "An error occured on the host system." + ); + assert!(!s.host_controller_error(), "An error occured on the xHC."); } -fn stop_and_reset() { - stop(); - wait_until_halt(); - reset(); +fn stop_and_reset(regs: &mut Registers) { + stop(regs); + wait_until_halt(regs); + reset(regs); } -fn stop() { - registers::handle(|r| { - r.operational.usbcmd.update_volatile(|u| { - u.clear_run_stop(); - }); +fn stop(regs: &mut Registers) { + regs.operational.usbcmd.update_volatile(|u| { + u.clear_run_stop(); }); } -fn wait_until_halt() { - registers::handle(|r| while !r.operational.usbsts.read_volatile().hc_halted() {}); +fn wait_until_halt(regs: &Registers) { + while !regs.operational.usbsts.read_volatile().hc_halted() {} } -fn reset() { - start_resetting(); - wait_until_reset_completed(); - wait_until_ready(); +fn reset(regs: &mut Registers) { + start_resetting(regs); + wait_until_reset_completed(regs); + wait_until_ready(regs); } -fn start_resetting() { - registers::handle(|r| { - r.operational.usbcmd.update_volatile(|u| { - u.set_host_controller_reset(); - }); +fn start_resetting(regs: &mut Registers) { + regs.operational.usbcmd.update_volatile(|u| { + u.set_host_controller_reset(); }); } -fn wait_until_reset_completed() { - registers::handle( - |r| { - while r.operational.usbcmd.read_volatile().host_controller_reset() {} - }, - ); +fn wait_until_reset_completed(regs: &Registers) { + while regs + .operational + .usbcmd + .read_volatile() + .host_controller_reset() + {} } -fn wait_until_ready() { - registers::handle( - |r| { - while r.operational.usbsts.read_volatile().controller_not_ready() {} - }, - ); +fn wait_until_ready(regs: &Registers) { + while regs + .operational + .usbsts + .read_volatile() + .controller_not_ready() + {} } -fn set_num_of_enabled_slots() { - let n = num_of_device_slots(); - registers::handle(|r| { - r.operational.config.update_volatile(|c| { - c.set_max_device_slots_enabled(n); - }); +fn set_num_of_enabled_slots(regs: &mut Registers) { + let n = num_of_device_slots(regs); + + regs.operational.config.update_volatile(|c| { + c.set_max_device_slots_enabled(n); }); } -fn num_of_device_slots() -> u8 { - registers::handle(|r| { - r.capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() - }) +fn num_of_device_slots(regs: &Registers) -> u8 { + regs.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() } From 66df7f0cf201dacd4aca9fea92792eba6b81e255 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 08:59:05 +0900 Subject: [PATCH 032/115] Unsafenize --- test/src/main.rs | 3 ++- test/src/registers.rs | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index f11be293..fd63e92d 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -22,7 +22,8 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let (_, memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); allocator::init(memory_map); - let mut regs = registers::get_accessor(); + // SAFETY: We are calling `get_accessor()` only once. + let mut regs = unsafe { registers::get_accessor() }; xhc::init(&mut regs); diff --git a/test/src/registers.rs b/test/src/registers.rs index 202e88e4..18659cd6 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -2,7 +2,10 @@ use crate::mapper::Mapper; pub type Registers = xhci::Registers; -pub fn get_accessor() -> Registers { +/// # Safety +/// +/// Multiple returned values must not exist in the same scope. +pub unsafe fn get_accessor() -> Registers { let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); let mmio_low = xhc_config_space.base_address_register(0); From 280510a81be5ebefc62e5b67963ee0f177561f40 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:07:14 +0900 Subject: [PATCH 033/115] No static --- test/src/event.rs | 24 +++--------------------- test/src/main.rs | 3 ++- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index 9901219d..9b9f5511 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -5,27 +5,9 @@ use qemu_print::qemu_println; use spinning_top::Spinlock; use xhci::ring::trb; -static EVENT_HANDLER: OnceCell> = OnceCell::uninit(); - const NUM_OF_TRBS_IN_RING: usize = 16; -pub fn init(regs: &mut Registers) { - let handler = EventHandler::new(regs); - - EVENT_HANDLER - .try_init_once(|| Spinlock::new(handler)) - .expect("EventHandler::new() called more than once"); - - EVENT_HANDLER - .get() - .unwrap_or_else(|| unreachable!("Should be initialized")) - .lock() - .init(regs); - - qemu_println!("Event rings and segment tables are initialized"); -} - -struct EventHandler { +pub struct EventHandler { segment_table: Vec, rings: Vec, @@ -35,7 +17,7 @@ struct EventHandler { cycle_bit: bool, } impl EventHandler { - fn new(regs: &Registers) -> Self { + pub fn new(regs: &Registers) -> Self { Self { segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings(regs).into()], rings: vec![EventRing::new(); number_of_rings(regs).into()], @@ -47,7 +29,7 @@ impl EventHandler { } } - fn init(&mut self, regs: &mut Registers) { + pub fn init(&mut self, regs: &mut Registers) { self.register_dequeue_pointer(regs); self.write_rings_addresses_in_table(); diff --git a/test/src/main.rs b/test/src/main.rs index fd63e92d..8320516f 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -13,6 +13,7 @@ mod registers; mod scratchpat; mod xhc; +use event::EventHandler; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; @@ -27,7 +28,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::init(&mut regs); - event::init(&mut regs); + let mut event_handler = EventHandler::new(&mut regs); command_ring::init(&mut regs); dcbaa::init(&mut regs); scratchpat::init(®s); From efd9ed062f3d29bc44d289bcb9461ff69d3bbf8f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:07:54 +0900 Subject: [PATCH 034/115] Init --- test/src/event.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index 9b9f5511..e8b3a00b 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -17,8 +17,8 @@ pub struct EventHandler { cycle_bit: bool, } impl EventHandler { - pub fn new(regs: &Registers) -> Self { - Self { + pub fn new(regs: &mut Registers) -> Self { + let mut v = Self { segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings(regs).into()], rings: vec![EventRing::new(); number_of_rings(regs).into()], @@ -26,10 +26,14 @@ impl EventHandler { dequeue_ptr_ring: 0, cycle_bit: true, - } + }; + + v.init(regs); + + v } - pub fn init(&mut self, regs: &mut Registers) { + fn init(&mut self, regs: &mut Registers) { self.register_dequeue_pointer(regs); self.write_rings_addresses_in_table(); From ee597224b0827490d7ba0f460bb310feeecfa554 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:09:31 +0900 Subject: [PATCH 035/115] No static --- test/src/command_ring.rs | 33 ++++++++------------------------- test/src/main.rs | 4 +++- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 3ef7ed65..b2cd844a 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,43 +1,26 @@ use crate::registers::Registers; use alloc::boxed::Box; -use conquer_once::spin::OnceCell; -use qemu_print::qemu_println; -use spinning_top::Spinlock; - -static COMMAND_RING_CONTROLLER: OnceCell> = OnceCell::uninit(); const NUM_OF_TRBS_IN_RING: usize = 10; -pub fn init(regs: &mut Registers) { - let controller = CommandRingController::new(); - - COMMAND_RING_CONTROLLER - .try_init_once(|| Spinlock::new(controller)) - .expect("CommandRingController::new() called more than once"); - - COMMAND_RING_CONTROLLER - .get() - .unwrap_or_else(|| unreachable!("Should be initialized")) - .lock() - .init(regs); - - qemu_println!("Command ring is initialized"); -} - -struct CommandRingController { +pub struct CommandRingController { ring: Box, enqueue_ptr: usize, cycle_bit: bool, } impl CommandRingController { - fn new() -> Self { - Self { + pub fn new(regs: &mut Registers) -> Self { + let mut v = Self { ring: Box::new(CommandRing::new()), enqueue_ptr: 0, cycle_bit: true, - } + }; + + v.init(regs); + + v } fn init(&mut self, regs: &mut Registers) { diff --git a/test/src/main.rs b/test/src/main.rs index 8320516f..daa69118 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -13,6 +13,7 @@ mod registers; mod scratchpat; mod xhc; +use command_ring::CommandRingController; use event::EventHandler; use qemu_exit::QEMUExit; use qemu_print::qemu_println; @@ -29,7 +30,8 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::init(&mut regs); let mut event_handler = EventHandler::new(&mut regs); - command_ring::init(&mut regs); + let mut command_ring = CommandRingController::new(&mut regs); + dcbaa::init(&mut regs); scratchpat::init(®s); From 70e1ed846fd714074e8a66f73e1c8ac57298b93e Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:10:21 +0900 Subject: [PATCH 036/115] No static --- test/src/dcbaa.rs | 27 ++++++--------------------- test/src/main.rs | 3 ++- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs index 119d142c..f81bdb64 100644 --- a/test/src/dcbaa.rs +++ b/test/src/dcbaa.rs @@ -1,30 +1,15 @@ use crate::registers::Registers; use alloc::vec; use alloc::vec::Vec; -use conquer_once::spin::OnceCell; -use qemu_print::qemu_println; -use spinning_top::Spinlock; -static DCBAA: OnceCell> = OnceCell::uninit(); - -pub fn init(regs: &mut Registers) { - DCBAA - .try_init_once(|| Spinlock::new(DeviceContextBaseAddressArray::new(regs))) - .expect("DeviceContextBaseAddressArray::new() called more than once"); +pub struct DeviceContextBaseAddressArray(Vec); +impl DeviceContextBaseAddressArray { + pub fn new(regs: &mut Registers) -> Self { + let mut v = Self(vec![RawDCBAA::new(); number_of_slots(regs)]); - DCBAA - .get() - .unwrap_or_else(|| unreachable!("Should be initialized")) - .lock() - .init(regs); + v.init(regs); - qemu_println!("Device Context Base Address Array is initialized"); -} - -struct DeviceContextBaseAddressArray(Vec); -impl DeviceContextBaseAddressArray { - fn new(regs: &Registers) -> Self { - Self(vec![RawDCBAA::new(); number_of_slots(regs)]) + v } fn init(&mut self, regs: &mut Registers) { diff --git a/test/src/main.rs b/test/src/main.rs index daa69118..320d9561 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -14,6 +14,7 @@ mod scratchpat; mod xhc; use command_ring::CommandRingController; +use dcbaa::DeviceContextBaseAddressArray; use event::EventHandler; use qemu_exit::QEMUExit; use qemu_print::qemu_println; @@ -32,7 +33,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let mut event_handler = EventHandler::new(&mut regs); let mut command_ring = CommandRingController::new(&mut regs); - dcbaa::init(&mut regs); + let mut dcbaa = DeviceContextBaseAddressArray::new(&mut regs); scratchpat::init(®s); xhc::run(&mut regs); From 728be740a1090eab50264aacee40288ae800db63 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:19:19 +0900 Subject: [PATCH 037/115] In struct --- test/src/xhc.rs | 136 +++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 60 deletions(-) diff --git a/test/src/xhc.rs b/test/src/xhc.rs index e26cd351..1a5a1202 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -4,8 +4,7 @@ use qemu_print::qemu_println; pub fn init(regs: &mut Registers) { qemu_println!("Initializing xHC..."); - stop_and_reset(regs); - set_num_of_enabled_slots(regs); + Initializer::new(regs).init(); qemu_println!("xHC is initialized."); } @@ -31,63 +30,80 @@ pub fn ensure_no_error_occurs(regs: &Registers) { assert!(!s.host_controller_error(), "An error occured on the xHC."); } -fn stop_and_reset(regs: &mut Registers) { - stop(regs); - wait_until_halt(regs); - reset(regs); +struct Initializer<'a> { + regs: &'a mut Registers, } - -fn stop(regs: &mut Registers) { - regs.operational.usbcmd.update_volatile(|u| { - u.clear_run_stop(); - }); -} - -fn wait_until_halt(regs: &Registers) { - while !regs.operational.usbsts.read_volatile().hc_halted() {} -} - -fn reset(regs: &mut Registers) { - start_resetting(regs); - wait_until_reset_completed(regs); - wait_until_ready(regs); -} - -fn start_resetting(regs: &mut Registers) { - regs.operational.usbcmd.update_volatile(|u| { - u.set_host_controller_reset(); - }); -} - -fn wait_until_reset_completed(regs: &Registers) { - while regs - .operational - .usbcmd - .read_volatile() - .host_controller_reset() - {} -} - -fn wait_until_ready(regs: &Registers) { - while regs - .operational - .usbsts - .read_volatile() - .controller_not_ready() - {} -} - -fn set_num_of_enabled_slots(regs: &mut Registers) { - let n = num_of_device_slots(regs); - - regs.operational.config.update_volatile(|c| { - c.set_max_device_slots_enabled(n); - }); -} - -fn num_of_device_slots(regs: &Registers) -> u8 { - regs.capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() +impl<'a> Initializer<'a> { + fn new(regs: &'a mut Registers) -> Self { + Self { regs } + } + + fn init(&mut self) { + self.stop_and_reset(); + self.set_num_of_enabled_slots(); + } + + fn stop_and_reset(&mut self) { + self.stop(); + self.wait_until_halt(); + self.reset(); + } + + fn reset(&mut self) { + self.start_resetting(); + self.wait_until_reset_completed(); + self.wait_until_ready(); + } + + fn start_resetting(&mut self) { + self.regs.operational.usbcmd.update_volatile(|u| { + u.set_host_controller_reset(); + }); + } + + fn wait_until_reset_completed(&mut self) { + while self + .regs + .operational + .usbcmd + .read_volatile() + .host_controller_reset() + {} + } + + fn wait_until_ready(&mut self) { + while self + .regs + .operational + .usbsts + .read_volatile() + .controller_not_ready() + {} + } + + fn wait_until_halt(&mut self) { + while !self.regs.operational.usbsts.read_volatile().hc_halted() {} + } + + fn set_num_of_enabled_slots(&mut self) { + let n = self.num_of_device_slots(); + + self.regs.operational.config.update_volatile(|c| { + c.set_max_device_slots_enabled(n); + }); + } + + fn stop(&mut self) { + self.regs.operational.usbcmd.update_volatile(|u| { + u.clear_run_stop(); + }); + } + + fn num_of_device_slots(&self) -> u8 { + self.regs + .capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() + } } From b4160b96c8ebf732de67509a0b834b60f67e939a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:22:43 +0900 Subject: [PATCH 038/115] Split --- test/src/xhc.rs | 52 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 1a5a1202..a0880d4e 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -49,6 +49,33 @@ impl<'a> Initializer<'a> { self.reset(); } + fn stop(&mut self) { + self.regs.operational.usbcmd.update_volatile(|u| { + u.clear_run_stop(); + }); + } + + fn wait_until_halt(&mut self) { + while !self.regs.operational.usbsts.read_volatile().hc_halted() {} + } + + fn reset(&mut self) { + Resetter::new(self.regs).reset(); + } + + fn set_num_of_enabled_slots(&mut self) { + SlotNumberSetter::new(self.regs).set(); + } +} + +struct Resetter<'a> { + regs: &'a mut Registers, +} +impl<'a> Resetter<'a> { + fn new(regs: &'a mut Registers) -> Self { + Self { regs } + } + fn reset(&mut self) { self.start_resetting(); self.wait_until_reset_completed(); @@ -61,7 +88,7 @@ impl<'a> Initializer<'a> { }); } - fn wait_until_reset_completed(&mut self) { + fn wait_until_reset_completed(&self) { while self .regs .operational @@ -71,7 +98,7 @@ impl<'a> Initializer<'a> { {} } - fn wait_until_ready(&mut self) { + fn wait_until_ready(&self) { while self .regs .operational @@ -80,26 +107,25 @@ impl<'a> Initializer<'a> { .controller_not_ready() {} } +} - fn wait_until_halt(&mut self) { - while !self.regs.operational.usbsts.read_volatile().hc_halted() {} +struct SlotNumberSetter<'a> { + regs: &'a mut Registers, +} +impl<'a> SlotNumberSetter<'a> { + fn new(regs: &'a mut Registers) -> Self { + Self { regs } } - fn set_num_of_enabled_slots(&mut self) { - let n = self.num_of_device_slots(); + fn set(&mut self) { + let n = self.number_of_slots(); self.regs.operational.config.update_volatile(|c| { c.set_max_device_slots_enabled(n); }); } - fn stop(&mut self) { - self.regs.operational.usbcmd.update_volatile(|u| { - u.clear_run_stop(); - }); - } - - fn num_of_device_slots(&self) -> u8 { + fn number_of_slots(&self) -> u8 { self.regs .capability .hcsparams1 From 31bf3db9be0a1448c7a33337cbf8b21419a7341f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:26:15 +0900 Subject: [PATCH 039/115] Op --- test/src/xhc.rs | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/test/src/xhc.rs b/test/src/xhc.rs index a0880d4e..052e691f 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,5 +1,7 @@ +use crate::mapper::Mapper; use crate::registers::Registers; use qemu_print::qemu_println; +use xhci::registers::Operational; pub fn init(regs: &mut Registers) { qemu_println!("Initializing xHC..."); @@ -60,7 +62,7 @@ impl<'a> Initializer<'a> { } fn reset(&mut self) { - Resetter::new(self.regs).reset(); + Resetter::new(&mut self.regs.operational).reset(); } fn set_num_of_enabled_slots(&mut self) { @@ -69,11 +71,11 @@ impl<'a> Initializer<'a> { } struct Resetter<'a> { - regs: &'a mut Registers, + op: &'a mut Operational, } impl<'a> Resetter<'a> { - fn new(regs: &'a mut Registers) -> Self { - Self { regs } + fn new(op: &'a mut Operational) -> Self { + Self { op } } fn reset(&mut self) { @@ -83,29 +85,17 @@ impl<'a> Resetter<'a> { } fn start_resetting(&mut self) { - self.regs.operational.usbcmd.update_volatile(|u| { + self.op.usbcmd.update_volatile(|u| { u.set_host_controller_reset(); }); } fn wait_until_reset_completed(&self) { - while self - .regs - .operational - .usbcmd - .read_volatile() - .host_controller_reset() - {} + while self.op.usbcmd.read_volatile().host_controller_reset() {} } fn wait_until_ready(&self) { - while self - .regs - .operational - .usbsts - .read_volatile() - .controller_not_ready() - {} + while self.op.usbsts.read_volatile().controller_not_ready() {} } } From 5f9b12737ef3e3ca4b1f043e66a8ea5509088a68 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:40:31 +0900 Subject: [PATCH 040/115] Fix --- test/src/event.rs | 56 +++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index e8b3a00b..4d878984 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -34,48 +34,66 @@ impl EventHandler { } fn init(&mut self, regs: &mut Registers) { - self.register_dequeue_pointer(regs); + EventHandlerInitializer::new(self, regs).init(); + } + + fn next_trb_addr(&self) -> u64 { + &self.segment_table[self.dequeue_ptr_segment as usize] as *const _ as u64 + + self.dequeue_ptr_ring as u64 * trb::BYTES as u64 + } +} + +struct EventHandlerInitializer<'a> { + handler: &'a mut EventHandler, + regs: &'a mut Registers, +} +impl<'a> EventHandlerInitializer<'a> { + fn new(handler: &'a mut EventHandler, regs: &'a mut Registers) -> Self { + Self { handler, regs } + } + fn init(&mut self) { + self.register_dequeue_pointer(); self.write_rings_addresses_in_table(); - self.register_table_size(regs); - self.enable_event_ring(regs); + self.register_table_size(); + self.enable_event_ring(); } - fn register_dequeue_pointer(&self, regs: &mut Registers) { - regs.interrupter_register_set + fn register_dequeue_pointer(&mut self) { + self.regs + .interrupter_register_set .interrupter_mut(0) .erdp - .update_volatile(|erdp| erdp.set_event_ring_dequeue_pointer(self.next_trb_addr())) + .update_volatile(|erdp| { + erdp.set_event_ring_dequeue_pointer(self.handler.next_trb_addr()) + }) } fn write_rings_addresses_in_table(&mut self) { - let mut segment_table = self.segment_table.clone(); + let mut segment_table = self.handler.segment_table.clone(); - for (i, ring) in self.rings.iter().enumerate() { + for (i, ring) in self.handler.rings.iter().enumerate() { segment_table[i].base_addr = ring as *const _ as u64; segment_table[i].segment_size = NUM_OF_TRBS_IN_RING as _; } } - fn register_table_size(&self, regs: &mut Registers) { - regs.interrupter_register_set + fn register_table_size(&mut self) { + self.regs + .interrupter_register_set .interrupter_mut(0) .erstsz .update_volatile(|erstsz| { - erstsz.set(self.segment_table.len() as u16); + erstsz.set(self.handler.segment_table.len() as u16); }) } - fn enable_event_ring(&self, regs: &mut Registers) { - regs.interrupter_register_set + fn enable_event_ring(&mut self) { + self.regs + .interrupter_register_set .interrupter_mut(0) .erstba - .update_volatile(|erstba| erstba.set(self.segment_table.as_ptr() as u64)) - } - - fn next_trb_addr(&self) -> u64 { - self.segment_table[self.dequeue_ptr_segment as usize].base_addr - + self.dequeue_ptr_ring as u64 * trb::BYTES as u64 + .update_volatile(|erstba| erstba.set(self.handler.segment_table.as_ptr() as u64)) } } From 4c77b478d12b09e270904e4de16a82501511ba2c Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:43:44 +0900 Subject: [PATCH 041/115] Fix --- test/src/event.rs | 2 +- test/src/main.rs | 2 +- test/src/xhc.rs | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index 4d878984..10be9e91 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -97,7 +97,7 @@ impl<'a> EventHandlerInitializer<'a> { } } -#[repr(C, packed)] +#[repr(C, align(64))] #[derive(Clone, Copy, Debug)] struct EventRingSegmentTableEntry { base_addr: u64, diff --git a/test/src/main.rs b/test/src/main.rs index 320d9561..0ad5815d 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -36,7 +36,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let mut dcbaa = DeviceContextBaseAddressArray::new(&mut regs); scratchpat::init(®s); - xhc::run(&mut regs); + xhc::run(&mut regs.operational); xhc::ensure_no_error_occurs(®s); let handler = qemu_exit::X86::new(0xf4, 33); diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 052e691f..bd2c26b7 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -11,14 +11,12 @@ pub fn init(regs: &mut Registers) { qemu_println!("xHC is initialized."); } -pub fn run(regs: &mut Registers) { - let o = &mut regs.operational; - - o.usbcmd.update_volatile(|u| { +pub fn run(op: &mut Operational) { + op.usbcmd.update_volatile(|u| { u.set_run_stop(); }); - while o.usbsts.read_volatile().hc_halted() {} + while op.usbsts.read_volatile().hc_halted() {} } pub fn ensure_no_error_occurs(regs: &Registers) { From 2641cb508c2ecf20103ff1fdd1a526ae6e01c08f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:47:24 +0900 Subject: [PATCH 042/115] Split --- test/src/xhc.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/test/src/xhc.rs b/test/src/xhc.rs index bd2c26b7..ac4ace53 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -45,18 +45,11 @@ impl<'a> Initializer<'a> { fn stop_and_reset(&mut self) { self.stop(); - self.wait_until_halt(); self.reset(); } fn stop(&mut self) { - self.regs.operational.usbcmd.update_volatile(|u| { - u.clear_run_stop(); - }); - } - - fn wait_until_halt(&mut self) { - while !self.regs.operational.usbsts.read_volatile().hc_halted() {} + Stopper::new(&mut self.regs.operational).stop(); } fn reset(&mut self) { @@ -68,6 +61,25 @@ impl<'a> Initializer<'a> { } } +struct Stopper<'a> { + op: &'a mut Operational, +} +impl<'a> Stopper<'a> { + fn new(op: &'a mut Operational) -> Self { + Self { op } + } + + fn stop(&mut self) { + self.op.usbcmd.update_volatile(|u| { + u.clear_run_stop(); + }); + } + + fn wait_until_halt(&mut self) { + while !self.op.usbsts.read_volatile().hc_halted() {} + } +} + struct Resetter<'a> { op: &'a mut Operational, } From 508119a8776e5968792037337c4fbc3cfaf8b01e Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 09:47:54 +0900 Subject: [PATCH 043/115] Remove --- test/src/xhc.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/src/xhc.rs b/test/src/xhc.rs index ac4ace53..f7c2235f 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -39,13 +39,9 @@ impl<'a> Initializer<'a> { } fn init(&mut self) { - self.stop_and_reset(); - self.set_num_of_enabled_slots(); - } - - fn stop_and_reset(&mut self) { self.stop(); self.reset(); + self.set_num_of_enabled_slots(); } fn stop(&mut self) { From 4324d5c20edb34456732a35c67b7069ef5617660 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 10:17:00 +0900 Subject: [PATCH 044/115] Read --- test/src/main.rs | 2 +- test/src/xhc.rs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index 0ad5815d..2c5d5420 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -37,7 +37,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> scratchpat::init(®s); xhc::run(&mut regs.operational); - xhc::ensure_no_error_occurs(®s); + xhc::ensure_no_error_occurs(®s.operational.usbsts.read_volatile()); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/xhc.rs b/test/src/xhc.rs index f7c2235f..f98cbc43 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,6 +1,7 @@ use crate::mapper::Mapper; use crate::registers::Registers; use qemu_print::qemu_println; +use xhci::registers::operational::UsbStatusRegister; use xhci::registers::Operational; pub fn init(regs: &mut Registers) { @@ -19,9 +20,7 @@ pub fn run(op: &mut Operational) { while op.usbsts.read_volatile().hc_halted() {} } -pub fn ensure_no_error_occurs(regs: &Registers) { - let s = regs.operational.usbsts.read_volatile(); - +pub fn ensure_no_error_occurs(s: &UsbStatusRegister) { assert!(!s.hc_halted(), "HC is halted."); assert!( !s.host_system_error(), @@ -69,9 +68,7 @@ impl<'a> Stopper<'a> { self.op.usbcmd.update_volatile(|u| { u.clear_run_stop(); }); - } - fn wait_until_halt(&mut self) { while !self.op.usbsts.read_volatile().hc_halted() {} } } From 9452de72ea4a4801fbedcb68072a585e063d9680 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 11:48:24 +0900 Subject: [PATCH 045/115] Fix the number of rings --- test/src/command_ring.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index b2cd844a..949de33c 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,7 +1,7 @@ use crate::registers::Registers; use alloc::boxed::Box; -const NUM_OF_TRBS_IN_RING: usize = 10; +const NUM_OF_TRBS_IN_RING: usize = 16; pub struct CommandRingController { ring: Box, From 056c6d77687e828a0b22ada8027f233347bcf9e4 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 13:31:46 +0900 Subject: [PATCH 046/115] Fix --- test/src/event.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index 10be9e91..3b0df063 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -18,9 +18,11 @@ pub struct EventHandler { } impl EventHandler { pub fn new(regs: &mut Registers) -> Self { + let number_of_rings = number_of_rings(regs); + let mut v = Self { - segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings(regs).into()], - rings: vec![EventRing::new(); number_of_rings(regs).into()], + segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings.into()], + rings: vec![EventRing::new(); number_of_rings.into()], dequeue_ptr_segment: 0, dequeue_ptr_ring: 0, @@ -70,7 +72,7 @@ impl<'a> EventHandlerInitializer<'a> { } fn write_rings_addresses_in_table(&mut self) { - let mut segment_table = self.handler.segment_table.clone(); + let mut segment_table = &mut self.handler.segment_table; for (i, ring) in self.handler.rings.iter().enumerate() { segment_table[i].base_addr = ring as *const _ as u64; From fcd1aea733aff09d54b68a56941e634f98379728 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 13:48:19 +0900 Subject: [PATCH 047/115] Template --- test/src/main.rs | 3 +++ test/src/ports.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/src/ports.rs diff --git a/test/src/main.rs b/test/src/main.rs index 2c5d5420..cd12fdf7 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -9,6 +9,7 @@ mod dcbaa; mod event; mod mapper; mod pci; +mod ports; mod registers; mod scratchpat; mod xhc; @@ -39,6 +40,8 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::run(&mut regs.operational); xhc::ensure_no_error_occurs(®s.operational.usbsts.read_volatile()); + ports::init_all_ports(®s); + let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } diff --git a/test/src/ports.rs b/test/src/ports.rs new file mode 100644 index 00000000..873b9d28 --- /dev/null +++ b/test/src/ports.rs @@ -0,0 +1,26 @@ +use crate::registers::Registers; + +pub fn init_all_ports(regs: &Registers) { + let num_ports = num_ports(regs); + + for port in 0..num_ports { + if connected(regs, port) { + init_port(regs, port); + } + } +} + +fn connected(regs: &Registers, port: u8) -> bool { + regs.port_register_set + .read_volatile_at(port.into()) + .portsc + .current_connect_status() +} + +fn init_port(regs: &Registers, port: u8) { + todo!() +} + +fn num_ports(regs: &Registers) -> u8 { + regs.capability.hcsparams1.read_volatile().number_of_ports() +} From 10b7ec756377640bdbd3d7468c234aaa533ed334 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 13:48:54 +0900 Subject: [PATCH 048/115] Add a mouse --- test/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Makefile b/test/Makefile index afa75225..5fd0b5e7 100644 --- a/test/Makefile +++ b/test/Makefile @@ -9,6 +9,7 @@ test: $(IMG) -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ -device qemu-xhci,id=xhci\ + -device usb-mouse \ -serial stdio \ -no-reboot \ -display none \ From 4c2b5ea71bd21cd0388c8e4072ab197e301d658f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 13 Dec 2023 18:44:35 +0900 Subject: [PATCH 049/115] Reset a port --- test/src/main.rs | 2 +- test/src/ports.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index cd12fdf7..1c528181 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -40,7 +40,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::run(&mut regs.operational); xhc::ensure_no_error_occurs(®s.operational.usbsts.read_volatile()); - ports::init_all_ports(®s); + ports::init_all_ports(&mut regs); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/ports.rs b/test/src/ports.rs index 873b9d28..71f61f50 100644 --- a/test/src/ports.rs +++ b/test/src/ports.rs @@ -1,6 +1,8 @@ +use xhci::registers::PortRegisterSet; + use crate::registers::Registers; -pub fn init_all_ports(regs: &Registers) { +pub fn init_all_ports(regs: &mut Registers) { let num_ports = num_ports(regs); for port in 0..num_ports { @@ -17,10 +19,65 @@ fn connected(regs: &Registers, port: u8) -> bool { .current_connect_status() } -fn init_port(regs: &Registers, port: u8) { - todo!() +fn init_port(regs: &mut Registers, port: u8) { + Resetter::new(regs, port).reset(); } fn num_ports(regs: &Registers) -> u8 { regs.capability.hcsparams1.read_volatile().number_of_ports() } + +struct Resetter<'a> { + regs: PortRegisterHandler<'a>, +} +impl<'a> Resetter<'a> { + fn new(regs: &'a mut Registers, port_number: u8) -> Self { + Self { + regs: PortRegisterHandler::new(regs, port_number), + } + } + + fn reset(mut self) { + self.start_resetting(); + self.wait_utnil_reset_completed(); + } + + fn start_resetting(&mut self) { + self.regs.update(|r| { + r.portsc.set_port_reset(); + }); + } + + fn wait_utnil_reset_completed(&self) { + while !self.reset_completed() {} + } + + fn reset_completed(&self) -> bool { + self.regs.read().portsc.port_reset_change() + } +} + +struct PortRegisterHandler<'a> { + regs: &'a mut Registers, + port_number: u8, +} +impl<'a> PortRegisterHandler<'a> { + fn new(regs: &'a mut Registers, port_number: u8) -> Self { + Self { regs, port_number } + } + + fn read(&self) -> PortRegisterSet { + self.regs + .port_register_set + .read_volatile_at(self.port_number.into()) + } + + fn update(&mut self, f: T) + where + T: FnOnce(&mut PortRegisterSet), + { + self.regs + .port_register_set + .update_volatile_at(self.port_number.into(), f) + } +} From 02b7d4d727e7809b81cdffa651d57e3b5e63ee8a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Thu, 14 Dec 2023 23:30:19 +0900 Subject: [PATCH 050/115] Exec a no-op --- test/src/command_ring.rs | 125 ++++++++++++++++++++++++++++++++++++++- test/src/event.rs | 77 ++++++++++++++++++++++-- test/src/main.rs | 6 ++ 3 files changed, 203 insertions(+), 5 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 949de33c..a80ee39e 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,5 +1,10 @@ -use crate::registers::Registers; +use crate::{event::EventHandler, registers::Registers}; use alloc::boxed::Box; +use qemu_print::qemu_println; +use xhci::ring::trb::{ + self, command, + event::{CommandCompletion, CompletionCode}, +}; const NUM_OF_TRBS_IN_RING: usize = 16; @@ -23,6 +28,32 @@ impl CommandRingController { v } + pub fn send_nop(&mut self, regs: &mut Registers, event_handler: &mut EventHandler) { + let trb = command::Noop::new(); + let trb = command::Allowed::Noop(trb); + + let on_completion = |c: CommandCompletion| { + assert_eq!( + c.completion_code(), + Ok(CompletionCode::Success), + "No-op command failed: {:?}", + c + ); + }; + + self.enqueue(regs, event_handler, trb, on_completion); + } + + fn enqueue( + &mut self, + regs: &mut Registers, + event_handler: &mut EventHandler, + trb: command::Allowed, + on_completion: impl Fn(CommandCompletion) + 'static, + ) { + Enqueuer::new(self, regs, event_handler).enqueue(trb, on_completion); + } + fn init(&mut self, regs: &mut Registers) { regs.operational.crcr.update_volatile(|crcr| { crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); @@ -31,6 +62,98 @@ impl CommandRingController { } } +struct Enqueuer<'a> { + controller: &'a mut CommandRingController, + regs: &'a mut Registers, + event_handler: &'a mut EventHandler, +} +impl<'a> Enqueuer<'a> { + fn new( + controller: &'a mut CommandRingController, + regs: &'a mut Registers, + event_handler: &'a mut EventHandler, + ) -> Self { + Self { + controller, + regs, + event_handler, + } + } + + fn enqueue( + &mut self, + mut trb: command::Allowed, + on_completion: impl Fn(CommandCompletion) + 'static, + ) { + self.modify_cycle_bit(&mut trb); + self.write_trb(trb); + self.register_handler(on_completion); + self.increment_enqueue_ptr(); + self.notify_command_is_sent(); + } + + fn enqueue_link(&mut self) { + let link_trb = *trb::Link::new().set_ring_segment_pointer(self.ring_head_address()); + let mut link_trb = command::Allowed::Link(link_trb); + + self.modify_cycle_bit(&mut link_trb); + self.write_trb(link_trb); + self.move_enqueue_ptr_to_head(); + } + + fn modify_cycle_bit(&mut self, trb: &mut command::Allowed) { + if self.controller.cycle_bit { + trb.set_cycle_bit(); + } else { + trb.clear_cycle_bit(); + } + } + + fn write_trb(&mut self, trb: command::Allowed) { + self.controller.ring.0[self.controller.enqueue_ptr] = trb.into_raw(); + } + + fn register_handler(&mut self, on_completion: impl Fn(CommandCompletion) + 'static) { + let trb_addr = self.written_trb_address(); + + self.event_handler.register_handler(trb_addr, move |c| { + on_completion(c); + }); + } + + fn written_trb_address(&self) -> u64 { + &self.controller.ring.0[self.controller.enqueue_ptr] as *const _ as u64 + } + + fn increment_enqueue_ptr(&mut self) { + self.controller.enqueue_ptr += 1; + + if !self.can_enqueue_trbs() { + self.enqueue_link(); + } + } + + fn notify_command_is_sent(&mut self) { + self.regs.doorbell.update_volatile_at(0, |r| { + r.set_doorbell_target(0); + }); + } + + fn can_enqueue_trbs(&self) -> bool { + // -1 for the space for a link TRB. + self.controller.enqueue_ptr < NUM_OF_TRBS_IN_RING - 1 + } + + fn move_enqueue_ptr_to_head(&mut self) { + self.controller.enqueue_ptr = 0; + self.controller.cycle_bit = !self.controller.cycle_bit; + } + + fn ring_head_address(&self) -> u64 { + self.controller.ring.as_ref() as *const _ as u64 + } +} + #[repr(C, align(64))] struct CommandRing([[u32; 4]; NUM_OF_TRBS_IN_RING]); impl CommandRing { diff --git a/test/src/event.rs b/test/src/event.rs index 3b0df063..a0036be3 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -1,9 +1,10 @@ use crate::registers::Registers; +use alloc::boxed::Box; use alloc::{vec, vec::Vec}; -use conquer_once::spin::OnceCell; +use bit_field::BitField; use qemu_print::qemu_println; -use spinning_top::Spinlock; -use xhci::ring::trb; +use xhci::ring::trb::{self, event::CommandCompletion}; +use xhci::ring::trb::{command, event}; const NUM_OF_TRBS_IN_RING: usize = 16; @@ -11,6 +12,10 @@ pub struct EventHandler { segment_table: Vec, rings: Vec, + // Alas, we cannot use `HashMap` because it's not in `alloc` yet. + // See https://github.com/rust-lang/rust/issues/27242. + handlers: Vec<(u64, Box)>, + dequeue_ptr_segment: u64, dequeue_ptr_ring: u64, @@ -23,6 +28,7 @@ impl EventHandler { let mut v = Self { segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings.into()], rings: vec![EventRing::new(); number_of_rings.into()], + handlers: Vec::new(), dequeue_ptr_segment: 0, dequeue_ptr_ring: 0, @@ -35,12 +41,75 @@ impl EventHandler { v } + pub fn register_handler<'a>( + &mut self, + trb_addr: u64, + handler: impl Fn(CommandCompletion) + 'static, + ) { + self.handlers.push((trb_addr, Box::new(handler))); + } + + pub fn process_trbs(&mut self) { + while !self.ring_is_empty() { + self.dequeue_and_process(); + } + } + + pub fn assert_all_commands_completed(&self) { + assert!(self.handlers.is_empty(), "Some commands are not completed"); + } + fn init(&mut self, regs: &mut Registers) { EventHandlerInitializer::new(self, regs).init(); } + fn dequeue_and_process(&mut self) { + assert!(!self.ring_is_empty()); + + let t = self.rings[self.dequeue_ptr_segment as usize].0[self.dequeue_ptr_ring as usize]; + let t = event::Allowed::try_from(t); + + if let Ok(event::Allowed::CommandCompletion(t)) = t { + let idx = self + .handlers + .iter() + .position(|(trb_addr, _)| *trb_addr == t.command_trb_pointer()) + .unwrap_or_else(|| panic!("No handler for {:?}", t)); + + let (_, handler) = self.handlers.remove(idx); + + handler(t); + } + + self.increment_ptr(); + } + + fn increment_ptr(&mut self) { + self.dequeue_ptr_ring += 1; + + if self.dequeue_ptr_ring >= NUM_OF_TRBS_IN_RING as u64 { + self.dequeue_ptr_ring = 0; + self.dequeue_ptr_segment += 1; + + if self.dequeue_ptr_segment >= self.segment_table.len() as u64 { + self.dequeue_ptr_segment = 0; + self.cycle_bit = !self.cycle_bit; + } + } + } + + fn ring_is_empty(&self) -> bool { + self.cycle_bit_of_next_trb() != self.cycle_bit + } + + fn cycle_bit_of_next_trb(&self) -> bool { + let t = self.rings[self.dequeue_ptr_segment as usize].0[self.dequeue_ptr_ring as usize]; + + t[3].get_bit(0) + } + fn next_trb_addr(&self) -> u64 { - &self.segment_table[self.dequeue_ptr_segment as usize] as *const _ as u64 + &self.rings[self.dequeue_ptr_segment as usize] as *const _ as u64 + self.dequeue_ptr_ring as u64 * trb::BYTES as u64 } } diff --git a/test/src/main.rs b/test/src/main.rs index 1c528181..6cfcaa17 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -40,8 +40,14 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::run(&mut regs.operational); xhc::ensure_no_error_occurs(®s.operational.usbsts.read_volatile()); + command_ring.send_nop(&mut regs, &mut event_handler); + + event_handler.process_trbs(); + ports::init_all_ports(&mut regs); + event_handler.assert_all_commands_completed(); + let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } From 923fcb7208c68388118447441a7f0302e25d94f5 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Fri, 15 Dec 2023 14:31:28 +0900 Subject: [PATCH 051/115] Implementing --- test/src/command_ring.rs | 48 ++++++- test/src/dcbaa.rs | 4 + test/src/main.rs | 5 +- test/src/ports.rs | 83 ----------- test/src/ports/context.rs | 77 ++++++++++ test/src/ports/endpoint.rs | 0 test/src/ports/mod.rs | 280 +++++++++++++++++++++++++++++++++++++ test/src/transfer_ring.rs | 26 ++++ 8 files changed, 437 insertions(+), 86 deletions(-) delete mode 100644 test/src/ports.rs create mode 100644 test/src/ports/context.rs create mode 100644 test/src/ports/endpoint.rs create mode 100644 test/src/ports/mod.rs create mode 100644 test/src/transfer_ring.rs diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index a80ee39e..5fe12ec4 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,6 +1,5 @@ use crate::{event::EventHandler, registers::Registers}; use alloc::boxed::Box; -use qemu_print::qemu_println; use xhci::ring::trb::{ self, command, event::{CommandCompletion, CompletionCode}, @@ -44,6 +43,53 @@ impl CommandRingController { self.enqueue(regs, event_handler, trb, on_completion); } + pub fn send_enable_slot( + &mut self, + regs: &mut Registers, + event_handler: &mut EventHandler, + after_enabling: impl Fn(u8) + 'static, + ) { + let trb = command::EnableSlot::new(); + let trb = command::Allowed::EnableSlot(trb); + + let on_completion = move |c: CommandCompletion| { + assert_eq!( + c.completion_code(), + Ok(CompletionCode::Success), + "Enable slot command failed: {:?}", + c + ); + + after_enabling(c.slot_id()); + }; + + self.enqueue(regs, event_handler, trb, on_completion); + } + + pub fn send_address_device( + &mut self, + regs: &mut Registers, + event_handler: &mut EventHandler, + input_cx_addr: u64, + slot: u8, + ) { + let trb = *command::AddressDevice::new() + .set_input_context_pointer(input_cx_addr) + .set_slot_id(slot); + let trb = command::Allowed::AddressDevice(trb); + + let on_completion = |c: CommandCompletion| { + assert_eq!( + c.completion_code(), + Ok(CompletionCode::Success), + "Address device command failed: {:?}", + c + ); + }; + + self.enqueue(regs, event_handler, trb, on_completion); + } + fn enqueue( &mut self, regs: &mut Registers, diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs index f81bdb64..4773938e 100644 --- a/test/src/dcbaa.rs +++ b/test/src/dcbaa.rs @@ -12,6 +12,10 @@ impl DeviceContextBaseAddressArray { v } + pub fn register_address(&mut self, port: u8, addr: u64) { + self.0[port as usize].0 = addr; + } + fn init(&mut self, regs: &mut Registers) { self.register_address_with_register(regs); } diff --git a/test/src/main.rs b/test/src/main.rs index 6cfcaa17..4d64bd3a 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -12,6 +12,7 @@ mod pci; mod ports; mod registers; mod scratchpat; +mod transfer_ring; mod xhc; use command_ring::CommandRingController; @@ -42,9 +43,9 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> command_ring.send_nop(&mut regs, &mut event_handler); - event_handler.process_trbs(); + ports::init_all_ports(&mut regs, &mut event_handler, &mut command_ring); - ports::init_all_ports(&mut regs); + event_handler.process_trbs(); event_handler.assert_all_commands_completed(); diff --git a/test/src/ports.rs b/test/src/ports.rs deleted file mode 100644 index 71f61f50..00000000 --- a/test/src/ports.rs +++ /dev/null @@ -1,83 +0,0 @@ -use xhci::registers::PortRegisterSet; - -use crate::registers::Registers; - -pub fn init_all_ports(regs: &mut Registers) { - let num_ports = num_ports(regs); - - for port in 0..num_ports { - if connected(regs, port) { - init_port(regs, port); - } - } -} - -fn connected(regs: &Registers, port: u8) -> bool { - regs.port_register_set - .read_volatile_at(port.into()) - .portsc - .current_connect_status() -} - -fn init_port(regs: &mut Registers, port: u8) { - Resetter::new(regs, port).reset(); -} - -fn num_ports(regs: &Registers) -> u8 { - regs.capability.hcsparams1.read_volatile().number_of_ports() -} - -struct Resetter<'a> { - regs: PortRegisterHandler<'a>, -} -impl<'a> Resetter<'a> { - fn new(regs: &'a mut Registers, port_number: u8) -> Self { - Self { - regs: PortRegisterHandler::new(regs, port_number), - } - } - - fn reset(mut self) { - self.start_resetting(); - self.wait_utnil_reset_completed(); - } - - fn start_resetting(&mut self) { - self.regs.update(|r| { - r.portsc.set_port_reset(); - }); - } - - fn wait_utnil_reset_completed(&self) { - while !self.reset_completed() {} - } - - fn reset_completed(&self) -> bool { - self.regs.read().portsc.port_reset_change() - } -} - -struct PortRegisterHandler<'a> { - regs: &'a mut Registers, - port_number: u8, -} -impl<'a> PortRegisterHandler<'a> { - fn new(regs: &'a mut Registers, port_number: u8) -> Self { - Self { regs, port_number } - } - - fn read(&self) -> PortRegisterSet { - self.regs - .port_register_set - .read_volatile_at(self.port_number.into()) - } - - fn update(&mut self, f: T) - where - T: FnOnce(&mut PortRegisterSet), - { - self.regs - .port_register_set - .update_volatile_at(self.port_number.into(), f) - } -} diff --git a/test/src/ports/context.rs b/test/src/ports/context.rs new file mode 100644 index 00000000..adb1d8ca --- /dev/null +++ b/test/src/ports/context.rs @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::registers::Registers; + +use { + alloc::boxed::Box, + xhci::context::{ + Device32Byte, Device64Byte, DeviceHandler, Input32Byte, Input64Byte, InputControlHandler, + InputHandler, + }, +}; + +pub struct Context { + pub input: Input, + pub output: Box, +} +impl Context { + pub fn new(regs: &Registers) -> Self { + Self { + input: Input::new(regs), + output: Device::new(regs).into(), + } + } +} + +pub(crate) enum Input { + Byte64(Box), + Byte32(Box), +} +impl Input { + pub fn control_mut(&mut self) -> &mut dyn InputControlHandler { + match self { + Self::Byte32(b32) => b32.control_mut(), + Self::Byte64(b64) => b64.control_mut(), + } + } + + pub fn device_mut(&mut self) -> &mut dyn DeviceHandler { + match self { + Self::Byte32(b32) => b32.device_mut(), + Self::Byte64(b64) => b64.device_mut(), + } + } + + pub fn phys_addr(&self) -> u64 { + match self { + Self::Byte32(b32) => b32.as_ref() as *const _ as u64, + Self::Byte64(b64) => b64.as_ref() as *const _ as u64, + } + } + + fn new(regs: &Registers) -> Self { + if csz(regs) { + Self::Byte64(Input64Byte::default().into()) + } else { + Self::Byte32(Input32Byte::default().into()) + } + } +} + +pub enum Device { + Byte64(Box), + Byte32(Box), +} +impl Device { + fn new(regs: &Registers) -> Self { + if csz(regs) { + Self::Byte64(Device64Byte::default().into()) + } else { + Self::Byte32(Device32Byte::default().into()) + } + } +} + +fn csz(regs: &Registers) -> bool { + regs.capability.hccparams1.read_volatile().context_size() +} diff --git a/test/src/ports/endpoint.rs b/test/src/ports/endpoint.rs new file mode 100644 index 00000000..e69de29b diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs new file mode 100644 index 00000000..bf0dd169 --- /dev/null +++ b/test/src/ports/mod.rs @@ -0,0 +1,280 @@ +mod context; + +use self::context::Context; +use crate::{ + command_ring::CommandRingController, dcbaa::DeviceContextBaseAddressArray, event::EventHandler, + registers::Registers, transfer_ring::TransferRingController, +}; +use qemu_print::qemu_println; +use xhci::{context::EndpointType, registers::PortRegisterSet, ring::trb::event}; + +pub fn init_all_ports( + regs: &mut Registers, + event_handler: &mut EventHandler, + cmd: &mut CommandRingController, +) { + let num_ports = num_ports(regs); + + for port in 0..num_ports { + if connected(regs, port) { + init_port(regs, event_handler, cmd, port); + } + } +} + +fn connected(regs: &Registers, port: u8) -> bool { + regs.port_register_set + .read_volatile_at(port.into()) + .portsc + .current_connect_status() +} + +fn init_port( + regs: &mut Registers, + event_handler: &mut EventHandler, + cmd: &mut CommandRingController, + port: u8, +) { + Resetter::new(regs, port).reset(); + // SlotEnabler::new(regs, event_handler, cmd).enable(move |slot| { + // qemu_println!("Slot {} enabled", slot); + + // StructureCreator::new( + // regs, + // port, + // slot, + // &mut DeviceContextBaseAddressArray::new(regs), + // cmd, + // event_handler, + // ) + // .create(); + // }); +} + +fn num_ports(regs: &Registers) -> u8 { + regs.capability.hcsparams1.read_volatile().number_of_ports() +} + +struct Resetter<'a> { + regs: PortRegisterHandler<'a>, +} +impl<'a> Resetter<'a> { + fn new(regs: &'a mut Registers, port_number: u8) -> Self { + Self { + regs: PortRegisterHandler::new(regs, port_number), + } + } + + fn reset(mut self) { + self.start_resetting(); + self.wait_utnil_reset_completed(); + } + + fn start_resetting(&mut self) { + self.regs.update(|r| { + r.portsc.set_port_reset(); + }); + } + + fn wait_utnil_reset_completed(&self) { + while !self.reset_completed() {} + } + + fn reset_completed(&self) -> bool { + self.regs.read().portsc.port_reset_change() + } +} + +struct SlotEnabler<'a> { + regs: &'a mut Registers, + event_handler: &'a mut EventHandler, + cmd: &'a mut CommandRingController, +} +impl<'a> SlotEnabler<'a> { + fn new( + regs: &'a mut Registers, + event_handler: &'a mut EventHandler, + cmd: &'a mut CommandRingController, + ) -> Self { + Self { + regs, + event_handler, + cmd, + } + } + + fn enable(&mut self, on_completion: impl Fn(u8) + 'static) { + self.cmd + .send_enable_slot(self.regs, self.event_handler, move |port_id| { + qemu_println!("Port {} enabled", port_id); + + on_completion(port_id); + }); + } +} + +struct StructureCreator<'a> { + regs: &'a mut Registers, + port: u8, + slot: u8, + dcbaa: &'a mut DeviceContextBaseAddressArray, + cmd: &'a mut CommandRingController, + event_handler: &'a mut EventHandler, + ring: TransferRingController, + cx: Context, +} +impl<'a> StructureCreator<'a> { + fn new( + regs: &'a mut Registers, + port: u8, + slot: u8, + dcbaa: &'a mut DeviceContextBaseAddressArray, + cmd: &'a mut CommandRingController, + event_handler: &'a mut EventHandler, + ) -> Self { + let cx = Context::new(regs); + + Self { + regs, + port, + slot, + dcbaa, + cmd, + event_handler, + ring: TransferRingController::new(), + cx, + } + } + + fn create(&mut self) { + self.init_input_context(); + self.init_ep0_context(); + self.register_with_dcbaa(); + self.issue_address_device_command(); + } + + fn init_input_context(&mut self) { + InputContextInitializer::new(&mut self.cx, self.port).init(); + } + + fn init_ep0_context(&mut self) { + Ep0ContextInitializer::new( + &mut self.cx, + self.port, + &self.ring, + PortRegisterHandler::new(self.regs, self.port), + ) + .init(); + } + + fn register_with_dcbaa(&mut self) { + self.dcbaa + .register_address(self.slot, self.cx.input.phys_addr()); + } + + fn issue_address_device_command(&mut self) { + self.cmd.send_address_device( + self.regs, + self.event_handler, + self.cx.input.phys_addr(), + self.slot, + ); + } +} + +struct InputContextInitializer<'a> { + cx: &'a mut Context, + port: u8, +} +impl<'a> InputContextInitializer<'a> { + fn new(cx: &'a mut Context, port: u8) -> Self { + Self { cx, port } + } + + fn init(&mut self) { + self.init_input_control(); + self.init_input_slot(); + } + + fn init_input_control(&mut self) { + let c = self.cx.input.control_mut(); + + c.set_add_context_flag(0); + c.set_add_context_flag(1); + } + + fn init_input_slot(&mut self) { + let s = self.cx.input.device_mut().slot_mut(); + + s.set_context_entries(1); + s.set_root_hub_port_number(self.port); + } +} + +struct Ep0ContextInitializer<'a> { + cx: &'a mut Context, + port: u8, + ring: &'a TransferRingController, + regs: PortRegisterHandler<'a>, +} +impl<'a> Ep0ContextInitializer<'a> { + fn new( + cx: &'a mut Context, + port: u8, + ring: &'a TransferRingController, + regs: PortRegisterHandler<'a>, + ) -> Self { + Self { + cx, + port, + ring, + regs, + } + } + + fn init(self) { + let s = self.get_max_packet_size(); + let ep_0 = self.cx.input.device_mut().endpoint_mut(1); + + ep_0.set_endpoint_type(EndpointType::Control); + ep_0.set_max_packet_size(s); + ep_0.set_tr_dequeue_pointer(self.ring.head_addr()); + ep_0.set_dequeue_cycle_state(); + ep_0.set_error_count(3); + } + + // TODO: Read the actual speed from xHCI supported protocol capability. + fn get_max_packet_size(&self) -> u16 { + match self.regs.read().portsc.port_speed() { + 1 | 3 => 64, + 2 => 8, + 4 => 512, + x => todo!("PSI: {}", x), + } + } +} + +struct PortRegisterHandler<'a> { + regs: &'a mut Registers, + port_number: u8, +} +impl<'a> PortRegisterHandler<'a> { + fn new(regs: &'a mut Registers, port_number: u8) -> Self { + Self { regs, port_number } + } + + fn read(&self) -> PortRegisterSet { + self.regs + .port_register_set + .read_volatile_at(self.port_number.into()) + } + + fn update(&mut self, f: T) + where + T: FnOnce(&mut PortRegisterSet), + { + self.regs + .port_register_set + .update_volatile_at(self.port_number.into(), f) + } +} diff --git a/test/src/transfer_ring.rs b/test/src/transfer_ring.rs new file mode 100644 index 00000000..c4d8c9de --- /dev/null +++ b/test/src/transfer_ring.rs @@ -0,0 +1,26 @@ +use alloc::boxed::Box; + +const NUM_OF_TRBS_IN_RING: usize = 16; + +pub struct TransferRingController { + ring: Box, +} +impl TransferRingController { + pub fn new() -> Self { + Self { + ring: Box::new(TransferRing::new()), + } + } + + pub fn head_addr(&self) -> u64 { + self.ring.as_ref() as *const _ as u64 + } +} + +#[repr(C, align(64))] +struct TransferRing([[u32; 4]; NUM_OF_TRBS_IN_RING]); +impl TransferRing { + fn new() -> Self { + Self([[0; 4]; NUM_OF_TRBS_IN_RING]) + } +} From e0027602c44ac1b519f2b0c62a5f22c36e927a36 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Fri, 15 Dec 2023 14:45:00 +0900 Subject: [PATCH 052/115] Add a README --- test/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test/README.md diff --git a/test/README.md b/test/README.md new file mode 100644 index 00000000..1baaea7b --- /dev/null +++ b/test/README.md @@ -0,0 +1,13 @@ +# Test program for the `xhci` crate + +## What is this? + +This is a tiny program to verify that the `xhci` crate defines data structures, register accessors, etc. correctly. + +You can use it as a reference for your own implementation. + +This program is designed based on [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf). + +## Running this program + +Just run `make test` in this directory. From ae6a78ff804c411809fbcb151637eb64987465d6 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Fri, 15 Dec 2023 23:52:13 +0900 Subject: [PATCH 053/115] Doc --- test/src/registers.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/src/registers.rs b/test/src/registers.rs index 18659cd6..a0cb7fbb 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -5,6 +5,11 @@ pub type Registers = xhci::Registers; /// # Safety /// /// Multiple returned values must not exist in the same scope. +// +// See [1] or [2] to understand this process. +// +// [1]: PCI - OSDev Wiki (https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231) +// [2]: USB 3.0 ホストドライバ自作入門 (https://booth.pm/ja/items/1056355) pub unsafe fn get_accessor() -> Registers { let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); @@ -13,5 +18,6 @@ pub unsafe fn get_accessor() -> Registers { let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; + // SAFETY: The caller ensures only one instance is created in a scope. unsafe { xhci::Registers::new(mmio_base, Mapper) } } From 3346d3a0de2ba01107371111d224e81847c0d12a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Fri, 15 Dec 2023 23:52:51 +0900 Subject: [PATCH 054/115] Docs --- test/src/registers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/registers.rs b/test/src/registers.rs index a0cb7fbb..35e92209 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -9,7 +9,7 @@ pub type Registers = xhci::Registers; // See [1] or [2] to understand this process. // // [1]: PCI - OSDev Wiki (https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231) -// [2]: USB 3.0 ホストドライバ自作入門 (https://booth.pm/ja/items/1056355) +// [2]: USB 3.0 ホストドライバ自作入門 第2章 (https://booth.pm/ja/items/1056355) pub unsafe fn get_accessor() -> Registers { let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); From e288ec4afe0b3194c20750e86d3c24c8d11394f3 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sat, 16 Dec 2023 00:03:10 +0900 Subject: [PATCH 055/115] README --- test/README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/README.md b/test/README.md index 1baaea7b..d0b977f5 100644 --- a/test/README.md +++ b/test/README.md @@ -2,9 +2,18 @@ ## What is this? -This is a tiny program to verify that the `xhci` crate defines data structures, register accessors, etc. correctly. +This is a tiny program to verify that the `xhci` crate defines data structures, register accessors, etc. correctly. It is a single UEFI binary, and when it runs, it does the following things: -You can use it as a reference for your own implementation. +- Find the xHCI controller. +- Initialize the controller. +- Enumerate and initialize all ports to which a device is connected. + +This program does not interact with each device because it is beyond the scope of this crate. + +You can use it as a reference for your own implementation, but note the following points: + +- While this program is a single UEFI binary, usually a UEFI binary is used as a bootloader, and interacting with the xHCI controller is done by the OS kernel. +- This program depends on the identity-mapping that is set up by the UEFI firmware, and thus, it uses Rust pointers as physical addresses directly. This program is designed based on [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf). From d3ec6ce7b2f0f6f4cbab8d5cb8437012e8e68a0a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 17 Dec 2023 01:02:28 +0900 Subject: [PATCH 056/115] Comment --- test/src/registers.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/src/registers.rs b/test/src/registers.rs index 35e92209..624728e6 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -5,14 +5,12 @@ pub type Registers = xhci::Registers; /// # Safety /// /// Multiple returned values must not exist in the same scope. -// -// See [1] or [2] to understand this process. -// -// [1]: PCI - OSDev Wiki (https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231) -// [2]: USB 3.0 ホストドライバ自作入門 第2章 (https://booth.pm/ja/items/1056355) pub unsafe fn get_accessor() -> Registers { let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); + // See [1] for the structure of base address registers. + // + // [1]: https://wiki.osdev.org/PCI#Base_Address_Registers let mmio_low = xhc_config_space.base_address_register(0); let mmio_high = xhc_config_space.base_address_register(1); From 22df3d4c1322adcb7ce44846c04a1b57dfda3a67 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 17 Dec 2023 01:06:45 +0900 Subject: [PATCH 057/115] Comment --- test/src/pci.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/src/pci.rs b/test/src/pci.rs index 4abd2e25..a02d815f 100644 --- a/test/src/pci.rs +++ b/test/src/pci.rs @@ -4,6 +4,9 @@ use x86_64::instructions::port::PortWrite; pub fn iter_xhc() -> impl Iterator { iter_devices().filter(|device| { + // The base class, sub class, and interface are defined in [1]. + // + // [1] eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2 Table 5-4 device.base_class() == 0x0c && device.sub_class() == 0x03 && device.interface() == 0x30 }) } From 121063559c7a6ec1b7aa6501116e21bf0b3c646e Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 17 Dec 2023 11:18:27 +0900 Subject: [PATCH 058/115] Docs --- test/src/pci.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/src/pci.rs b/test/src/pci.rs index a02d815f..862a7550 100644 --- a/test/src/pci.rs +++ b/test/src/pci.rs @@ -62,6 +62,10 @@ impl ConfigSpace { Self { address } } + // See [1] for the structure of the PCI configuration space for xHCI. + // + // [1]: eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2 Figure 5-1. + pub fn base_address_register(&self, index: u8) -> u32 { assert!(index < 6, "index must be less than 6"); @@ -121,11 +125,17 @@ impl ConfigSpaceReader { unsafe fn read(&self, offset: u8) -> u32 { assert!(offset < 32, "offset must be less than 32"); - unsafe { PortWrite::write_to_port(Self::CONFIG_ADDRESS, self.as_u32(offset)) }; + // The method of how to read values from the PCI configuration space is described in [1]. + // + // [1]: https://wiki.osdev.org/PCI#Configuration_Space + unsafe { PortWrite::write_to_port(Self::CONFIG_ADDRESS, self.config_addr(offset)) }; unsafe { PortRead::read_from_port(Self::CONFIG_DATA) } } - fn as_u32(&self, offset: u8) -> u32 { + // See [1] for the description of bits in the PCI configuration address. + // + // [1]: https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231 + fn config_addr(&self, offset: u8) -> u32 { let mut result = 0; result.set_bits(2..=7, offset.into()); From 6b195bc0f5d3e4557abf1d3c139c3d0f484031ca Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 17 Dec 2023 11:22:07 +0900 Subject: [PATCH 059/115] Docs --- test/src/registers.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/src/registers.rs b/test/src/registers.rs index 624728e6..b2f8ac58 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -1,3 +1,5 @@ +use bit_field::BitField; + use crate::mapper::Mapper; pub type Registers = xhci::Registers; @@ -14,6 +16,13 @@ pub unsafe fn get_accessor() -> Registers { let mmio_low = xhc_config_space.base_address_register(0); let mmio_high = xhc_config_space.base_address_register(1); + let bar_type = mmio_low.get_bits(1..=2); + + assert_eq!( + bar_type, 2, + "The MMIO of xHC must be mapped to memory and 64-bit wide." + ); + let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; // SAFETY: The caller ensures only one instance is created in a scope. From 1f1ac75d0947629f7b5c2305ed15066134b00ab3 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 17 Dec 2023 23:13:00 +0900 Subject: [PATCH 060/115] README --- test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/README.md b/test/README.md index d0b977f5..295d1d0c 100644 --- a/test/README.md +++ b/test/README.md @@ -2,7 +2,7 @@ ## What is this? -This is a tiny program to verify that the `xhci` crate defines data structures, register accessors, etc. correctly. It is a single UEFI binary, and when it runs, it does the following things: +This is a tiny program to verify that the `xhci` crate defines data structures, register accessors, etc. correctly, and to demostrate how to use the crate. It is a single UEFI binary, and when it runs, it does the following things: - Find the xHCI controller. - Initialize the controller. From 64cd674505de22272364ab1b040bae5ca743ff3b Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 17 Dec 2023 23:57:36 +0900 Subject: [PATCH 061/115] Follow the spec --- test/src/xhc.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/src/xhc.rs b/test/src/xhc.rs index f98cbc43..adf445ea 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -38,11 +38,22 @@ impl<'a> Initializer<'a> { } fn init(&mut self) { + self.wait_until_controller_is_ready(); self.stop(); self.reset(); self.set_num_of_enabled_slots(); } + fn wait_until_controller_is_ready(&self) { + while self + .regs + .operational + .usbsts + .read_volatile() + .controller_not_ready() + {} + } + fn stop(&mut self) { Stopper::new(&mut self.regs.operational).stop(); } From 83407358a6e70e5d6e66f0c1ac69a7a20bc04ce6 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:17:49 +0900 Subject: [PATCH 062/115] Add the `all` target --- test/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/Makefile b/test/Makefile index 5fd0b5e7..503300b0 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,6 +3,8 @@ EFI = ../target/x86_64-unknown-uefi/debug/xhci-test.efi .PHONY: test clean +all: $(IMG) + test: $(IMG) qemu-system-x86_64 \ -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \ From 3d55f851a897055953c76b2de0bcdfb885675140 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:25:41 +0900 Subject: [PATCH 063/115] Shared ref --- test/src/event.rs | 3 +-- test/src/main.rs | 26 +++++++++++++++++--------- test/src/ports/mod.rs | 2 +- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index a0036be3..1b671c0e 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -2,9 +2,8 @@ use crate::registers::Registers; use alloc::boxed::Box; use alloc::{vec, vec::Vec}; use bit_field::BitField; -use qemu_print::qemu_println; +use xhci::ring::trb::event; use xhci::ring::trb::{self, event::CommandCompletion}; -use xhci::ring::trb::{command, event}; const NUM_OF_TRBS_IN_RING: usize = 16; diff --git a/test/src/main.rs b/test/src/main.rs index 4d64bd3a..3114f982 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -15,6 +15,9 @@ mod scratchpat; mod transfer_ring; mod xhc; +use core::cell::RefCell; + +use alloc::rc::Rc; use command_ring::CommandRingController; use dcbaa::DeviceContextBaseAddressArray; use event::EventHandler; @@ -29,21 +32,26 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> // SAFETY: We are calling `get_accessor()` only once. let mut regs = unsafe { registers::get_accessor() }; + let regs = Rc::new(RefCell::new(regs)); - xhc::init(&mut regs); + xhc::init(&mut regs.borrow_mut()); - let mut event_handler = EventHandler::new(&mut regs); - let mut command_ring = CommandRingController::new(&mut regs); + let mut event_handler = EventHandler::new(&mut regs.borrow_mut()); + let mut command_ring = CommandRingController::new(&mut regs.borrow_mut()); - let mut dcbaa = DeviceContextBaseAddressArray::new(&mut regs); - scratchpat::init(®s); + let mut dcbaa = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); + scratchpat::init(®s.borrow()); - xhc::run(&mut regs.operational); - xhc::ensure_no_error_occurs(®s.operational.usbsts.read_volatile()); + xhc::run(&mut regs.borrow_mut().operational); + xhc::ensure_no_error_occurs(®s.borrow().operational.usbsts.read_volatile()); - command_ring.send_nop(&mut regs, &mut event_handler); + command_ring.send_nop(&mut regs.borrow_mut(), &mut event_handler); - ports::init_all_ports(&mut regs, &mut event_handler, &mut command_ring); + ports::init_all_ports( + &mut regs.borrow_mut(), + &mut event_handler, + &mut command_ring, + ); event_handler.process_trbs(); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index bf0dd169..84bd7b9d 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -6,7 +6,7 @@ use crate::{ registers::Registers, transfer_ring::TransferRingController, }; use qemu_print::qemu_println; -use xhci::{context::EndpointType, registers::PortRegisterSet, ring::trb::event}; +use xhci::{context::EndpointType, registers::PortRegisterSet}; pub fn init_all_ports( regs: &mut Registers, From 69a6a0e5523c6976f62d09b964e7b7246e2b049c Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:29:36 +0900 Subject: [PATCH 064/115] Shared ref --- test/src/command_ring.rs | 12 +++++++++--- test/src/event.rs | 2 +- test/src/main.rs | 8 ++++---- test/src/ports/mod.rs | 7 +------ 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 5fe12ec4..03c8036f 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,5 +1,7 @@ +use core::cell::RefCell; + use crate::{event::EventHandler, registers::Registers}; -use alloc::boxed::Box; +use alloc::{boxed::Box, rc::Rc}; use xhci::ring::trb::{ self, command, event::{CommandCompletion, CompletionCode}, @@ -10,19 +12,23 @@ const NUM_OF_TRBS_IN_RING: usize = 16; pub struct CommandRingController { ring: Box, + regs: Rc>, + enqueue_ptr: usize, cycle_bit: bool, } impl CommandRingController { - pub fn new(regs: &mut Registers) -> Self { + pub fn new(regs: &Rc>) -> Self { let mut v = Self { ring: Box::new(CommandRing::new()), + regs: Rc::clone(regs), + enqueue_ptr: 0, cycle_bit: true, }; - v.init(regs); + v.init(&mut regs.borrow_mut()); v } diff --git a/test/src/event.rs b/test/src/event.rs index 1b671c0e..22e8d826 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -140,7 +140,7 @@ impl<'a> EventHandlerInitializer<'a> { } fn write_rings_addresses_in_table(&mut self) { - let mut segment_table = &mut self.handler.segment_table; + let segment_table = &mut self.handler.segment_table; for (i, ring) in self.handler.rings.iter().enumerate() { segment_table[i].base_addr = ring as *const _ as u64; diff --git a/test/src/main.rs b/test/src/main.rs index 3114f982..ba58bf4b 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -31,15 +31,15 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> allocator::init(memory_map); // SAFETY: We are calling `get_accessor()` only once. - let mut regs = unsafe { registers::get_accessor() }; - let regs = Rc::new(RefCell::new(regs)); + let regs = unsafe { registers::get_accessor() }; + let mut regs = Rc::new(RefCell::new(regs)); xhc::init(&mut regs.borrow_mut()); let mut event_handler = EventHandler::new(&mut regs.borrow_mut()); - let mut command_ring = CommandRingController::new(&mut regs.borrow_mut()); + let mut command_ring = CommandRingController::new(&mut regs); - let mut dcbaa = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); + let _ = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); scratchpat::init(®s.borrow()); xhc::run(&mut regs.borrow_mut().operational); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 84bd7b9d..ed3df628 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -29,12 +29,7 @@ fn connected(regs: &Registers, port: u8) -> bool { .current_connect_status() } -fn init_port( - regs: &mut Registers, - event_handler: &mut EventHandler, - cmd: &mut CommandRingController, - port: u8, -) { +fn init_port(regs: &mut Registers, _: &mut EventHandler, _: &mut CommandRingController, port: u8) { Resetter::new(regs, port).reset(); // SlotEnabler::new(regs, event_handler, cmd).enable(move |slot| { // qemu_println!("Slot {} enabled", slot); From 930c4b5a32bcda182b9dd03f8808d11149e102fa Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:30:38 +0900 Subject: [PATCH 065/115] No parameter --- test/src/command_ring.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 03c8036f..09a632b6 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -28,7 +28,7 @@ impl CommandRingController { cycle_bit: true, }; - v.init(&mut regs.borrow_mut()); + v.init(); v } @@ -106,7 +106,9 @@ impl CommandRingController { Enqueuer::new(self, regs, event_handler).enqueue(trb, on_completion); } - fn init(&mut self, regs: &mut Registers) { + fn init(&mut self) { + let regs = &mut self.regs.borrow_mut(); + regs.operational.crcr.update_volatile(|crcr| { crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); crcr.set_ring_cycle_state(); From b8162c431e3f475b3f46b44fb05235b8873396d6 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:35:08 +0900 Subject: [PATCH 066/115] Shared ref --- test/src/command_ring.rs | 25 +++++++++---------------- test/src/main.rs | 2 +- test/src/ports/mod.rs | 10 +++------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 09a632b6..1adc393b 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -33,7 +33,7 @@ impl CommandRingController { v } - pub fn send_nop(&mut self, regs: &mut Registers, event_handler: &mut EventHandler) { + pub fn send_nop(&mut self, event_handler: &mut EventHandler) { let trb = command::Noop::new(); let trb = command::Allowed::Noop(trb); @@ -46,12 +46,11 @@ impl CommandRingController { ); }; - self.enqueue(regs, event_handler, trb, on_completion); + self.enqueue(event_handler, trb, on_completion); } pub fn send_enable_slot( &mut self, - regs: &mut Registers, event_handler: &mut EventHandler, after_enabling: impl Fn(u8) + 'static, ) { @@ -69,12 +68,11 @@ impl CommandRingController { after_enabling(c.slot_id()); }; - self.enqueue(regs, event_handler, trb, on_completion); + self.enqueue(event_handler, trb, on_completion); } pub fn send_address_device( &mut self, - regs: &mut Registers, event_handler: &mut EventHandler, input_cx_addr: u64, slot: u8, @@ -93,17 +91,16 @@ impl CommandRingController { ); }; - self.enqueue(regs, event_handler, trb, on_completion); + self.enqueue(event_handler, trb, on_completion); } fn enqueue( &mut self, - regs: &mut Registers, event_handler: &mut EventHandler, trb: command::Allowed, on_completion: impl Fn(CommandCompletion) + 'static, ) { - Enqueuer::new(self, regs, event_handler).enqueue(trb, on_completion); + Enqueuer::new(self, event_handler).enqueue(trb, on_completion); } fn init(&mut self) { @@ -118,18 +115,12 @@ impl CommandRingController { struct Enqueuer<'a> { controller: &'a mut CommandRingController, - regs: &'a mut Registers, event_handler: &'a mut EventHandler, } impl<'a> Enqueuer<'a> { - fn new( - controller: &'a mut CommandRingController, - regs: &'a mut Registers, - event_handler: &'a mut EventHandler, - ) -> Self { + fn new(controller: &'a mut CommandRingController, event_handler: &'a mut EventHandler) -> Self { Self { controller, - regs, event_handler, } } @@ -188,7 +179,9 @@ impl<'a> Enqueuer<'a> { } fn notify_command_is_sent(&mut self) { - self.regs.doorbell.update_volatile_at(0, |r| { + let regs = &mut self.controller.regs.borrow_mut(); + + regs.doorbell.update_volatile_at(0, |r| { r.set_doorbell_target(0); }); } diff --git a/test/src/main.rs b/test/src/main.rs index ba58bf4b..c6c22abc 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -45,7 +45,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::run(&mut regs.borrow_mut().operational); xhc::ensure_no_error_occurs(®s.borrow().operational.usbsts.read_volatile()); - command_ring.send_nop(&mut regs.borrow_mut(), &mut event_handler); + command_ring.send_nop(&mut event_handler); ports::init_all_ports( &mut regs.borrow_mut(), diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index ed3df628..64317579 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -100,7 +100,7 @@ impl<'a> SlotEnabler<'a> { fn enable(&mut self, on_completion: impl Fn(u8) + 'static) { self.cmd - .send_enable_slot(self.regs, self.event_handler, move |port_id| { + .send_enable_slot(self.event_handler, move |port_id| { qemu_println!("Port {} enabled", port_id); on_completion(port_id); @@ -168,12 +168,8 @@ impl<'a> StructureCreator<'a> { } fn issue_address_device_command(&mut self) { - self.cmd.send_address_device( - self.regs, - self.event_handler, - self.cx.input.phys_addr(), - self.slot, - ); + self.cmd + .send_address_device(self.event_handler, self.cx.input.phys_addr(), self.slot); } } From 47b3973eee43a71eaae99d79dff18c944ab0084f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:41:39 +0900 Subject: [PATCH 067/115] Shared --- test/src/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index c6c22abc..c80051c9 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -37,6 +37,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::init(&mut regs.borrow_mut()); let mut event_handler = EventHandler::new(&mut regs.borrow_mut()); + let mut event_handler = Rc::new(RefCell::new(event_handler)); let mut command_ring = CommandRingController::new(&mut regs); let _ = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); @@ -45,17 +46,17 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::run(&mut regs.borrow_mut().operational); xhc::ensure_no_error_occurs(®s.borrow().operational.usbsts.read_volatile()); - command_ring.send_nop(&mut event_handler); + command_ring.send_nop(&mut event_handler.borrow_mut()); ports::init_all_ports( &mut regs.borrow_mut(), - &mut event_handler, + &mut event_handler.borrow_mut(), &mut command_ring, ); - event_handler.process_trbs(); + event_handler.borrow_mut().process_trbs(); - event_handler.assert_all_commands_completed(); + event_handler.borrow_mut().assert_all_commands_completed(); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); From ab4f332ede54a69e4480cfe9a0fe37fd8831d333 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:46:16 +0900 Subject: [PATCH 068/115] Shared ref --- test/src/command_ring.rs | 4 +++- test/src/main.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 1adc393b..3e8c8c02 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -12,16 +12,18 @@ const NUM_OF_TRBS_IN_RING: usize = 16; pub struct CommandRingController { ring: Box, + event_handler: Rc>, regs: Rc>, enqueue_ptr: usize, cycle_bit: bool, } impl CommandRingController { - pub fn new(regs: &Rc>) -> Self { + pub fn new(regs: &Rc>, event_handler: &Rc>) -> Self { let mut v = Self { ring: Box::new(CommandRing::new()), + event_handler: Rc::clone(event_handler), regs: Rc::clone(regs), enqueue_ptr: 0, diff --git a/test/src/main.rs b/test/src/main.rs index c80051c9..3136ba64 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -38,7 +38,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let mut event_handler = EventHandler::new(&mut regs.borrow_mut()); let mut event_handler = Rc::new(RefCell::new(event_handler)); - let mut command_ring = CommandRingController::new(&mut regs); + let mut command_ring = CommandRingController::new(&mut regs, &event_handler); let _ = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); scratchpat::init(®s.borrow()); From 26b1a2f2ec4b78595c5f76802c8dd43012695b94 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:47:51 +0900 Subject: [PATCH 069/115] Shared --- test/src/command_ring.rs | 29 ++++++++++------------------- test/src/main.rs | 2 +- test/src/ports/mod.rs | 2 +- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 3e8c8c02..fc2217d0 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -35,7 +35,7 @@ impl CommandRingController { v } - pub fn send_nop(&mut self, event_handler: &mut EventHandler) { + pub fn send_nop(&mut self) { let trb = command::Noop::new(); let trb = command::Allowed::Noop(trb); @@ -48,7 +48,7 @@ impl CommandRingController { ); }; - self.enqueue(event_handler, trb, on_completion); + self.enqueue(trb, on_completion); } pub fn send_enable_slot( @@ -70,15 +70,10 @@ impl CommandRingController { after_enabling(c.slot_id()); }; - self.enqueue(event_handler, trb, on_completion); + self.enqueue(trb, on_completion); } - pub fn send_address_device( - &mut self, - event_handler: &mut EventHandler, - input_cx_addr: u64, - slot: u8, - ) { + pub fn send_address_device(&mut self, input_cx_addr: u64, slot: u8) { let trb = *command::AddressDevice::new() .set_input_context_pointer(input_cx_addr) .set_slot_id(slot); @@ -93,16 +88,15 @@ impl CommandRingController { ); }; - self.enqueue(event_handler, trb, on_completion); + self.enqueue(trb, on_completion); } fn enqueue( &mut self, - event_handler: &mut EventHandler, trb: command::Allowed, on_completion: impl Fn(CommandCompletion) + 'static, ) { - Enqueuer::new(self, event_handler).enqueue(trb, on_completion); + Enqueuer::new(self).enqueue(trb, on_completion); } fn init(&mut self) { @@ -117,14 +111,10 @@ impl CommandRingController { struct Enqueuer<'a> { controller: &'a mut CommandRingController, - event_handler: &'a mut EventHandler, } impl<'a> Enqueuer<'a> { - fn new(controller: &'a mut CommandRingController, event_handler: &'a mut EventHandler) -> Self { - Self { - controller, - event_handler, - } + fn new(controller: &'a mut CommandRingController) -> Self { + Self { controller } } fn enqueue( @@ -162,8 +152,9 @@ impl<'a> Enqueuer<'a> { fn register_handler(&mut self, on_completion: impl Fn(CommandCompletion) + 'static) { let trb_addr = self.written_trb_address(); + let event_handler = &mut self.controller.event_handler.borrow_mut(); - self.event_handler.register_handler(trb_addr, move |c| { + event_handler.register_handler(trb_addr, move |c| { on_completion(c); }); } diff --git a/test/src/main.rs b/test/src/main.rs index 3136ba64..f3825f48 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -46,7 +46,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> xhc::run(&mut regs.borrow_mut().operational); xhc::ensure_no_error_occurs(®s.borrow().operational.usbsts.read_volatile()); - command_ring.send_nop(&mut event_handler.borrow_mut()); + command_ring.send_nop(); ports::init_all_ports( &mut regs.borrow_mut(), diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 64317579..d6e7ddaa 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -169,7 +169,7 @@ impl<'a> StructureCreator<'a> { fn issue_address_device_command(&mut self) { self.cmd - .send_address_device(self.event_handler, self.cx.input.phys_addr(), self.slot); + .send_address_device(self.cx.input.phys_addr(), self.slot); } } From 102fda91c8cc634ce0e76a61f9824aa6c0c9769f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:48:15 +0900 Subject: [PATCH 070/115] Shared --- test/src/command_ring.rs | 6 +----- test/src/ports/mod.rs | 9 ++++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index fc2217d0..c40d6d7c 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -51,11 +51,7 @@ impl CommandRingController { self.enqueue(trb, on_completion); } - pub fn send_enable_slot( - &mut self, - event_handler: &mut EventHandler, - after_enabling: impl Fn(u8) + 'static, - ) { + pub fn send_enable_slot(&mut self, after_enabling: impl Fn(u8) + 'static) { let trb = command::EnableSlot::new(); let trb = command::Allowed::EnableSlot(trb); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index d6e7ddaa..1122f7cc 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -99,12 +99,11 @@ impl<'a> SlotEnabler<'a> { } fn enable(&mut self, on_completion: impl Fn(u8) + 'static) { - self.cmd - .send_enable_slot(self.event_handler, move |port_id| { - qemu_println!("Port {} enabled", port_id); + self.cmd.send_enable_slot(move |port_id| { + qemu_println!("Port {} enabled", port_id); - on_completion(port_id); - }); + on_completion(port_id); + }); } } From 48bda5e2907b7bcf7680387fe88f1d3c130b4ed8 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 11:56:36 +0900 Subject: [PATCH 071/115] Shared --- test/src/command_ring.rs | 3 +-- test/src/main.rs | 17 ++--------------- test/src/xhc.rs | 32 ++++++++++++++++++++++++++++---- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index c40d6d7c..a77aed1a 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,7 +1,6 @@ -use core::cell::RefCell; - use crate::{event::EventHandler, registers::Registers}; use alloc::{boxed::Box, rc::Rc}; +use core::cell::RefCell; use xhci::ring::trb::{ self, command, event::{CommandCompletion, CompletionCode}, diff --git a/test/src/main.rs b/test/src/main.rs index f3825f48..21ac2c3d 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -18,9 +18,6 @@ mod xhc; use core::cell::RefCell; use alloc::rc::Rc; -use command_ring::CommandRingController; -use dcbaa::DeviceContextBaseAddressArray; -use event::EventHandler; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; @@ -32,19 +29,9 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> // SAFETY: We are calling `get_accessor()` only once. let regs = unsafe { registers::get_accessor() }; - let mut regs = Rc::new(RefCell::new(regs)); + let regs = Rc::new(RefCell::new(regs)); - xhc::init(&mut regs.borrow_mut()); - - let mut event_handler = EventHandler::new(&mut regs.borrow_mut()); - let mut event_handler = Rc::new(RefCell::new(event_handler)); - let mut command_ring = CommandRingController::new(&mut regs, &event_handler); - - let _ = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); - scratchpat::init(®s.borrow()); - - xhc::run(&mut regs.borrow_mut().operational); - xhc::ensure_no_error_occurs(®s.borrow().operational.usbsts.read_volatile()); + let (event_handler, mut command_ring, _) = xhc::init(®s); command_ring.send_nop(); diff --git a/test/src/xhc.rs b/test/src/xhc.rs index adf445ea..980f963c 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,18 +1,42 @@ +use crate::command_ring::CommandRingController; +use crate::dcbaa::DeviceContextBaseAddressArray; +use crate::event::EventHandler; use crate::mapper::Mapper; use crate::registers::Registers; +use crate::scratchpat; +use alloc::rc::Rc; +use core::cell::RefCell; use qemu_print::qemu_println; use xhci::registers::operational::UsbStatusRegister; use xhci::registers::Operational; -pub fn init(regs: &mut Registers) { +pub fn init( + regs: &Rc>, +) -> ( + Rc>, + CommandRingController, + DeviceContextBaseAddressArray, +) { qemu_println!("Initializing xHC..."); - Initializer::new(regs).init(); + Initializer::new(&mut regs.borrow_mut()).init(); + + let event_handler = EventHandler::new(&mut regs.borrow_mut()); + let event_handler = Rc::new(RefCell::new(event_handler)); + let command_ring = CommandRingController::new(®s, &event_handler); + + let dcbaa = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); + scratchpat::init(®s.borrow()); + + run(&mut regs.borrow_mut().operational); + ensure_no_error_occurs(®s.borrow().operational.usbsts.read_volatile()); qemu_println!("xHC is initialized."); + + (event_handler, command_ring, dcbaa) } -pub fn run(op: &mut Operational) { +fn run(op: &mut Operational) { op.usbcmd.update_volatile(|u| { u.set_run_stop(); }); @@ -20,7 +44,7 @@ pub fn run(op: &mut Operational) { while op.usbsts.read_volatile().hc_halted() {} } -pub fn ensure_no_error_occurs(s: &UsbStatusRegister) { +fn ensure_no_error_occurs(s: &UsbStatusRegister) { assert!(!s.hc_halted(), "HC is halted."); assert!( !s.host_system_error(), From 64890841019664151eeed9ad7a9fc35256653fa0 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 12:14:46 +0900 Subject: [PATCH 072/115] Polling --- test/README.md | 2 +- test/src/event.rs | 12 ++++++++++ test/src/xhc.rs | 56 +++++++++++++++++++---------------------------- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/test/README.md b/test/README.md index 295d1d0c..b8d0bfaa 100644 --- a/test/README.md +++ b/test/README.md @@ -15,7 +15,7 @@ You can use it as a reference for your own implementation, but note the followin - While this program is a single UEFI binary, usually a UEFI binary is used as a bootloader, and interacting with the xHCI controller is done by the OS kernel. - This program depends on the identity-mapping that is set up by the UEFI firmware, and thus, it uses Rust pointers as physical addresses directly. -This program is designed based on [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf). +This program is designed based on [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf). In the source code, "xHCI spec" refers to this document. ## Running this program diff --git a/test/src/event.rs b/test/src/event.rs index 22e8d826..b42843ed 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -125,6 +125,7 @@ impl<'a> EventHandlerInitializer<'a> { fn init(&mut self) { self.register_dequeue_pointer(); self.write_rings_addresses_in_table(); + self.disable_interrupts(); self.register_table_size(); self.enable_event_ring(); } @@ -148,6 +149,17 @@ impl<'a> EventHandlerInitializer<'a> { } } + // We use polling for simplicity. + fn disable_interrupts(&mut self) { + self.regs + .interrupter_register_set + .interrupter_mut(0) + .iman + .update_volatile(|iman| { + iman.clear_interrupt_enable(); + }) + } + fn register_table_size(&mut self) { self.regs .interrupter_register_set diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 980f963c..30691b9d 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -10,6 +10,9 @@ use qemu_print::qemu_println; use xhci::registers::operational::UsbStatusRegister; use xhci::registers::Operational; +/// Initializes the host controller according to 4.2 of xHCI spec. +/// +/// Note that we do not enable interrupts as it is optional and for simplicity. pub fn init( regs: &Rc>, ) -> ( @@ -19,10 +22,14 @@ pub fn init( ) { qemu_println!("Initializing xHC..."); - Initializer::new(&mut regs.borrow_mut()).init(); + wait_until_controller_is_ready(®s.borrow()); + stop(&mut regs.borrow_mut()); + reset(&mut regs.borrow_mut()); + set_num_of_enabled_slots(&mut regs.borrow_mut()); let event_handler = EventHandler::new(&mut regs.borrow_mut()); let event_handler = Rc::new(RefCell::new(event_handler)); + let command_ring = CommandRingController::new(®s, &event_handler); let dcbaa = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); @@ -53,42 +60,25 @@ fn ensure_no_error_occurs(s: &UsbStatusRegister) { assert!(!s.host_controller_error(), "An error occured on the xHC."); } -struct Initializer<'a> { - regs: &'a mut Registers, +fn wait_until_controller_is_ready(regs: &Registers) { + while regs + .operational + .usbsts + .read_volatile() + .controller_not_ready() + {} } -impl<'a> Initializer<'a> { - fn new(regs: &'a mut Registers) -> Self { - Self { regs } - } - fn init(&mut self) { - self.wait_until_controller_is_ready(); - self.stop(); - self.reset(); - self.set_num_of_enabled_slots(); - } - - fn wait_until_controller_is_ready(&self) { - while self - .regs - .operational - .usbsts - .read_volatile() - .controller_not_ready() - {} - } - - fn stop(&mut self) { - Stopper::new(&mut self.regs.operational).stop(); - } +fn stop(regs: &mut Registers) { + Stopper::new(&mut regs.operational).stop(); +} - fn reset(&mut self) { - Resetter::new(&mut self.regs.operational).reset(); - } +fn reset(regs: &mut Registers) { + Resetter::new(&mut regs.operational).reset(); +} - fn set_num_of_enabled_slots(&mut self) { - SlotNumberSetter::new(self.regs).set(); - } +fn set_num_of_enabled_slots(regs: &mut Registers) { + SlotNumberSetter::new(regs).set(); } struct Stopper<'a> { From 28fc89c7c942dbd414d6c69de8ce1a4eff835784 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 12:15:42 +0900 Subject: [PATCH 073/115] Process immediately --- test/src/command_ring.rs | 2 ++ test/src/main.rs | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index a77aed1a..01a454cd 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -92,6 +92,8 @@ impl CommandRingController { on_completion: impl Fn(CommandCompletion) + 'static, ) { Enqueuer::new(self).enqueue(trb, on_completion); + + self.event_handler.borrow_mut().process_trbs(); } fn init(&mut self) { diff --git a/test/src/main.rs b/test/src/main.rs index 21ac2c3d..ebe045c2 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -41,8 +41,6 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> &mut command_ring, ); - event_handler.borrow_mut().process_trbs(); - event_handler.borrow_mut().assert_all_commands_completed(); let handler = qemu_exit::X86::new(0xf4, 33); From 3f4614c8ca63924fb6a6698244216fbbcb7bbd8f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 13:01:35 +0900 Subject: [PATCH 074/115] Shared --- test/src/main.rs | 6 +++--- test/src/xhc.rs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index ebe045c2..8ed6ac22 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -31,14 +31,14 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let regs = unsafe { registers::get_accessor() }; let regs = Rc::new(RefCell::new(regs)); - let (event_handler, mut command_ring, _) = xhc::init(®s); + let (event_handler, command_ring, _) = xhc::init(®s); - command_ring.send_nop(); + command_ring.borrow_mut().send_nop(); ports::init_all_ports( &mut regs.borrow_mut(), &mut event_handler.borrow_mut(), - &mut command_ring, + &mut command_ring.borrow_mut(), ); event_handler.borrow_mut().assert_all_commands_completed(); diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 30691b9d..4ba9d01f 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -17,7 +17,7 @@ pub fn init( regs: &Rc>, ) -> ( Rc>, - CommandRingController, + Rc>, DeviceContextBaseAddressArray, ) { qemu_println!("Initializing xHC..."); @@ -31,6 +31,7 @@ pub fn init( let event_handler = Rc::new(RefCell::new(event_handler)); let command_ring = CommandRingController::new(®s, &event_handler); + let command_ring = Rc::new(RefCell::new(command_ring)); let dcbaa = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); scratchpat::init(®s.borrow()); From 09c5b1bd674cc00b4e8ead6393393997aeef4c41 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 15:57:06 +0900 Subject: [PATCH 075/115] Fix the makefile --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index 503300b0..48510579 100644 --- a/test/Makefile +++ b/test/Makefile @@ -31,7 +31,7 @@ $(IMG): $(EFI) build mmd -i $@ ::/efi/boot mcopy -i $@ $(EFI) ::/efi/boot/bootx64.efi -$(EFI): $(wildcard src/*.rs) Cargo.toml +$(EFI): $(wildcard src/**/*.rs) Cargo.toml cargo build build: From 9cf7bb061ff92c15cae861078aab5018645a3b18 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 17:26:56 +0900 Subject: [PATCH 076/115] Doing --- test/src/command_ring.rs | 82 +++++++-------------------------- test/src/event.rs | 4 +- test/src/main.rs | 20 ++++---- test/src/ports/mod.rs | 99 +++++++++++++++++++++------------------- test/src/xhc.rs | 5 +- 5 files changed, 84 insertions(+), 126 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 01a454cd..94907ba5 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,28 +1,23 @@ -use crate::{event::EventHandler, registers::Registers}; +use crate::registers::Registers; use alloc::{boxed::Box, rc::Rc}; use core::cell::RefCell; -use xhci::ring::trb::{ - self, command, - event::{CommandCompletion, CompletionCode}, -}; +use xhci::ring::trb::{self, command}; const NUM_OF_TRBS_IN_RING: usize = 16; pub struct CommandRingController { ring: Box, - event_handler: Rc>, regs: Rc>, enqueue_ptr: usize, cycle_bit: bool, } impl CommandRingController { - pub fn new(regs: &Rc>, event_handler: &Rc>) -> Self { + pub fn new(regs: &Rc>) -> Self { let mut v = Self { ring: Box::new(CommandRing::new()), - event_handler: Rc::clone(event_handler), regs: Rc::clone(regs), enqueue_ptr: 0, @@ -34,66 +29,31 @@ impl CommandRingController { v } - pub fn send_nop(&mut self) { + pub fn send_nop(&mut self) -> u64 { let trb = command::Noop::new(); let trb = command::Allowed::Noop(trb); - let on_completion = |c: CommandCompletion| { - assert_eq!( - c.completion_code(), - Ok(CompletionCode::Success), - "No-op command failed: {:?}", - c - ); - }; - - self.enqueue(trb, on_completion); + self.enqueue(trb) } - pub fn send_enable_slot(&mut self, after_enabling: impl Fn(u8) + 'static) { + pub fn send_enable_slot(&mut self) -> u64 { let trb = command::EnableSlot::new(); let trb = command::Allowed::EnableSlot(trb); - let on_completion = move |c: CommandCompletion| { - assert_eq!( - c.completion_code(), - Ok(CompletionCode::Success), - "Enable slot command failed: {:?}", - c - ); - - after_enabling(c.slot_id()); - }; - - self.enqueue(trb, on_completion); + self.enqueue(trb) } - pub fn send_address_device(&mut self, input_cx_addr: u64, slot: u8) { + pub fn send_address_device(&mut self, input_cx_addr: u64, slot: u8) -> u64 { let trb = *command::AddressDevice::new() .set_input_context_pointer(input_cx_addr) .set_slot_id(slot); let trb = command::Allowed::AddressDevice(trb); - let on_completion = |c: CommandCompletion| { - assert_eq!( - c.completion_code(), - Ok(CompletionCode::Success), - "Address device command failed: {:?}", - c - ); - }; - - self.enqueue(trb, on_completion); + self.enqueue(trb) } - fn enqueue( - &mut self, - trb: command::Allowed, - on_completion: impl Fn(CommandCompletion) + 'static, - ) { - Enqueuer::new(self).enqueue(trb, on_completion); - - self.event_handler.borrow_mut().process_trbs(); + fn enqueue<'a>(&'a mut self, trb: command::Allowed) -> u64 { + Enqueuer::new(self).enqueue(trb) } fn init(&mut self) { @@ -114,16 +74,15 @@ impl<'a> Enqueuer<'a> { Self { controller } } - fn enqueue( - &mut self, - mut trb: command::Allowed, - on_completion: impl Fn(CommandCompletion) + 'static, - ) { + fn enqueue(&mut self, mut trb: command::Allowed) -> u64 { + let addr = self.written_trb_address(); + self.modify_cycle_bit(&mut trb); self.write_trb(trb); - self.register_handler(on_completion); self.increment_enqueue_ptr(); self.notify_command_is_sent(); + + addr } fn enqueue_link(&mut self) { @@ -147,15 +106,6 @@ impl<'a> Enqueuer<'a> { self.controller.ring.0[self.controller.enqueue_ptr] = trb.into_raw(); } - fn register_handler(&mut self, on_completion: impl Fn(CommandCompletion) + 'static) { - let trb_addr = self.written_trb_address(); - let event_handler = &mut self.controller.event_handler.borrow_mut(); - - event_handler.register_handler(trb_addr, move |c| { - on_completion(c); - }); - } - fn written_trb_address(&self) -> u64 { &self.controller.ring.0[self.controller.enqueue_ptr] as *const _ as u64 } diff --git a/test/src/event.rs b/test/src/event.rs index b42843ed..982c5a03 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -13,7 +13,7 @@ pub struct EventHandler { // Alas, we cannot use `HashMap` because it's not in `alloc` yet. // See https://github.com/rust-lang/rust/issues/27242. - handlers: Vec<(u64, Box)>, + handlers: Vec<(u64, Box)>, dequeue_ptr_segment: u64, dequeue_ptr_ring: u64, @@ -43,7 +43,7 @@ impl EventHandler { pub fn register_handler<'a>( &mut self, trb_addr: u64, - handler: impl Fn(CommandCompletion) + 'static, + handler: impl FnOnce(CommandCompletion) + 'static, ) { self.handlers.push((trb_addr, Box::new(handler))); } diff --git a/test/src/main.rs b/test/src/main.rs index 8ed6ac22..3c3c0e16 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -15,12 +15,12 @@ mod scratchpat; mod transfer_ring; mod xhc; -use core::cell::RefCell; - use alloc::rc::Rc; +use core::cell::RefCell; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; +use xhci::ring::trb::event::CompletionCode; #[uefi::entry] fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { @@ -33,14 +33,18 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let (event_handler, command_ring, _) = xhc::init(®s); - command_ring.borrow_mut().send_nop(); + let nop_addr = command_ring.borrow_mut().send_nop(); + event_handler.borrow_mut().register_handler(nop_addr, |c| { + assert_eq!( + c.completion_code(), + Ok(CompletionCode::Success), + "NOP failed." + ); + }); - ports::init_all_ports( - &mut regs.borrow_mut(), - &mut event_handler.borrow_mut(), - &mut command_ring.borrow_mut(), - ); + ports::init_all_ports(regs, event_handler.clone(), command_ring); + event_handler.borrow_mut().process_trbs(); event_handler.borrow_mut().assert_all_commands_completed(); let handler = qemu_exit::X86::new(0xf4, 33); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 1122f7cc..de29e55d 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -5,19 +5,21 @@ use crate::{ command_ring::CommandRingController, dcbaa::DeviceContextBaseAddressArray, event::EventHandler, registers::Registers, transfer_ring::TransferRingController, }; +use alloc::rc::Rc; +use core::cell::RefCell; use qemu_print::qemu_println; use xhci::{context::EndpointType, registers::PortRegisterSet}; pub fn init_all_ports( - regs: &mut Registers, - event_handler: &mut EventHandler, - cmd: &mut CommandRingController, + regs: Rc>, + event_handler: Rc>, + cmd: Rc>, ) { - let num_ports = num_ports(regs); + let num_ports = num_ports(®s.borrow()); for port in 0..num_ports { - if connected(regs, port) { - init_port(regs, event_handler, cmd, port); + if connected(®s.borrow(), port) { + init_port(regs.clone(), event_handler.clone(), cmd.clone(), port); } } } @@ -29,21 +31,25 @@ fn connected(regs: &Registers, port: u8) -> bool { .current_connect_status() } -fn init_port(regs: &mut Registers, _: &mut EventHandler, _: &mut CommandRingController, port: u8) { - Resetter::new(regs, port).reset(); - // SlotEnabler::new(regs, event_handler, cmd).enable(move |slot| { - // qemu_println!("Slot {} enabled", slot); - - // StructureCreator::new( - // regs, - // port, - // slot, - // &mut DeviceContextBaseAddressArray::new(regs), - // cmd, - // event_handler, - // ) - // .create(); - // }); +fn init_port( + regs: Rc>, + event_handler: Rc>, + cmd: Rc>, + port: u8, +) { + Resetter::new(&mut regs.borrow_mut(), port).reset(); + + let addr = cmd.borrow_mut().send_enable_slot(); + + event_handler.borrow_mut().register_handler(addr, |c| { + assert_eq!( + c.completion_code(), + Ok(xhci::ring::trb::event::CompletionCode::Success), + "Enable slot failed." + ); + + qemu_println!("Slot enabled."); + }); } fn num_ports(regs: &Registers) -> u8 { @@ -80,16 +86,16 @@ impl<'a> Resetter<'a> { } } -struct SlotEnabler<'a> { - regs: &'a mut Registers, - event_handler: &'a mut EventHandler, - cmd: &'a mut CommandRingController, +struct SlotEnabler { + regs: Rc>, + event_handler: Rc>, + cmd: Rc>, } -impl<'a> SlotEnabler<'a> { +impl SlotEnabler { fn new( - regs: &'a mut Registers, - event_handler: &'a mut EventHandler, - cmd: &'a mut CommandRingController, + regs: Rc>, + event_handler: Rc>, + cmd: Rc>, ) -> Self { Self { regs, @@ -98,36 +104,31 @@ impl<'a> SlotEnabler<'a> { } } - fn enable(&mut self, on_completion: impl Fn(u8) + 'static) { - self.cmd.send_enable_slot(move |port_id| { - qemu_println!("Port {} enabled", port_id); - - on_completion(port_id); - }); + fn enable(&mut self) -> u64 { + self.cmd.borrow_mut().send_enable_slot() } } -struct StructureCreator<'a> { - regs: &'a mut Registers, +struct StructureInitializer { + regs: Rc>, port: u8, slot: u8, - dcbaa: &'a mut DeviceContextBaseAddressArray, - cmd: &'a mut CommandRingController, - event_handler: &'a mut EventHandler, + dcbaa: Rc>, + cmd: Rc>, + event_handler: Rc>, ring: TransferRingController, cx: Context, } -impl<'a> StructureCreator<'a> { +impl StructureInitializer { fn new( - regs: &'a mut Registers, + regs: Rc>, port: u8, slot: u8, - dcbaa: &'a mut DeviceContextBaseAddressArray, - cmd: &'a mut CommandRingController, - event_handler: &'a mut EventHandler, + dcbaa: Rc>, + cmd: Rc>, + event_handler: Rc>, + cx: Context, ) -> Self { - let cx = Context::new(regs); - Self { regs, port, @@ -156,18 +157,20 @@ impl<'a> StructureCreator<'a> { &mut self.cx, self.port, &self.ring, - PortRegisterHandler::new(self.regs, self.port), + PortRegisterHandler::new(&mut self.regs.borrow_mut(), self.port), ) .init(); } fn register_with_dcbaa(&mut self) { self.dcbaa + .borrow_mut() .register_address(self.slot, self.cx.input.phys_addr()); } fn issue_address_device_command(&mut self) { self.cmd + .borrow_mut() .send_address_device(self.cx.input.phys_addr(), self.slot); } } diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 4ba9d01f..0ac241fa 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -18,7 +18,7 @@ pub fn init( ) -> ( Rc>, Rc>, - DeviceContextBaseAddressArray, + Rc>, ) { qemu_println!("Initializing xHC..."); @@ -30,10 +30,11 @@ pub fn init( let event_handler = EventHandler::new(&mut regs.borrow_mut()); let event_handler = Rc::new(RefCell::new(event_handler)); - let command_ring = CommandRingController::new(®s, &event_handler); + let command_ring = CommandRingController::new(®s); let command_ring = Rc::new(RefCell::new(command_ring)); let dcbaa = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); + let dcbaa = Rc::new(RefCell::new(dcbaa)); scratchpat::init(®s.borrow()); run(&mut regs.borrow_mut().operational); From 1f1467b00f56546b93a7d51c7b54512e39fb835c Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 18:11:33 +0900 Subject: [PATCH 077/115] Doing --- test/src/main.rs | 4 ++-- test/src/ports/mod.rs | 42 ++++++++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index 3c3c0e16..8d4bd8fb 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -31,7 +31,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let regs = unsafe { registers::get_accessor() }; let regs = Rc::new(RefCell::new(regs)); - let (event_handler, command_ring, _) = xhc::init(®s); + let (event_handler, command_ring, dcbaa) = xhc::init(®s); let nop_addr = command_ring.borrow_mut().send_nop(); event_handler.borrow_mut().register_handler(nop_addr, |c| { @@ -42,7 +42,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> ); }); - ports::init_all_ports(regs, event_handler.clone(), command_ring); + ports::init_all_ports(regs, event_handler.clone(), command_ring, dcbaa); event_handler.borrow_mut().process_trbs(); event_handler.borrow_mut().assert_all_commands_completed(); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index de29e55d..52592c22 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -14,12 +14,19 @@ pub fn init_all_ports( regs: Rc>, event_handler: Rc>, cmd: Rc>, + dcbaa: Rc>, ) { let num_ports = num_ports(®s.borrow()); for port in 0..num_ports { if connected(®s.borrow(), port) { - init_port(regs.clone(), event_handler.clone(), cmd.clone(), port); + init_port( + regs.clone(), + event_handler.clone(), + cmd.clone(), + dcbaa.clone(), + port, + ); } } } @@ -35,21 +42,36 @@ fn init_port( regs: Rc>, event_handler: Rc>, cmd: Rc>, + dcbaa: Rc>, port: u8, ) { Resetter::new(&mut regs.borrow_mut(), port).reset(); let addr = cmd.borrow_mut().send_enable_slot(); - event_handler.borrow_mut().register_handler(addr, |c| { - assert_eq!( - c.completion_code(), - Ok(xhci::ring::trb::event::CompletionCode::Success), - "Enable slot failed." - ); - - qemu_println!("Slot enabled."); - }); + event_handler + .clone() + .borrow_mut() + .register_handler(addr, move |c| { + assert_eq!( + c.completion_code(), + Ok(xhci::ring::trb::event::CompletionCode::Success), + "Enable slot failed." + ); + + qemu_println!("Slot enabled."); + + StructureInitializer::new( + regs.clone(), + port, + c.slot_id(), + dcbaa, + cmd.clone(), + event_handler.clone(), + Context::new(®s.borrow()), + ) + .create() + }); } fn num_ports(regs: &Registers) -> u8 { From b25e983e0d00aa6c22fd49e6baea00e77fc695a4 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 19:39:02 +0900 Subject: [PATCH 078/115] I love static --- test/src/command_ring.rs | 34 ++++---- test/src/dcbaa.rs | 37 +++++---- test/src/event.rs | 86 +++++++++++--------- test/src/main.rs | 10 +-- test/src/ports/context.rs | 20 ++--- test/src/ports/mod.rs | 87 ++++++++------------ test/src/registers.rs | 30 +++++-- test/src/scratchpat.rs | 15 ++-- test/src/xhc.rs | 167 ++++++++++++++++++++------------------ 9 files changed, 250 insertions(+), 236 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 94907ba5..483cb534 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,25 +1,21 @@ -use crate::registers::Registers; -use alloc::{boxed::Box, rc::Rc}; -use core::cell::RefCell; +use alloc::boxed::Box; use xhci::ring::trb::{self, command}; +use crate::registers; + const NUM_OF_TRBS_IN_RING: usize = 16; pub struct CommandRingController { ring: Box, - regs: Rc>, - enqueue_ptr: usize, cycle_bit: bool, } impl CommandRingController { - pub fn new(regs: &Rc>) -> Self { + pub fn new() -> Self { let mut v = Self { ring: Box::new(CommandRing::new()), - regs: Rc::clone(regs), - enqueue_ptr: 0, cycle_bit: true, }; @@ -57,12 +53,12 @@ impl CommandRingController { } fn init(&mut self) { - let regs = &mut self.regs.borrow_mut(); - - regs.operational.crcr.update_volatile(|crcr| { - crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); - crcr.set_ring_cycle_state(); - }); + registers::handle(|r| { + r.operational.crcr.update_volatile(|crcr| { + crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); + crcr.set_ring_cycle_state(); + }); + }) } } @@ -119,11 +115,11 @@ impl<'a> Enqueuer<'a> { } fn notify_command_is_sent(&mut self) { - let regs = &mut self.controller.regs.borrow_mut(); - - regs.doorbell.update_volatile_at(0, |r| { - r.set_doorbell_target(0); - }); + registers::handle(|r| { + r.doorbell.update_volatile_at(0, |r| { + r.set_doorbell_target(0); + }); + }) } fn can_enqueue_trbs(&self) -> bool { diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs index 4773938e..5e3830e2 100644 --- a/test/src/dcbaa.rs +++ b/test/src/dcbaa.rs @@ -1,13 +1,14 @@ -use crate::registers::Registers; use alloc::vec; use alloc::vec::Vec; +use crate::registers; + pub struct DeviceContextBaseAddressArray(Vec); impl DeviceContextBaseAddressArray { - pub fn new(regs: &mut Registers) -> Self { - let mut v = Self(vec![RawDCBAA::new(); number_of_slots(regs)]); + pub fn new() -> Self { + let mut v = Self(vec![RawDCBAA::new(); number_of_slots()]); - v.init(regs); + v.init(); v } @@ -16,14 +17,16 @@ impl DeviceContextBaseAddressArray { self.0[port as usize].0 = addr; } - fn init(&mut self, regs: &mut Registers) { - self.register_address_with_register(regs); + fn init(&mut self) { + self.register_address_with_register(); } - fn register_address_with_register(&self, regs: &mut Registers) { - regs.operational - .dcbaap - .update_volatile(|dcbaap| dcbaap.set(self.0.as_ptr() as u64)); + fn register_address_with_register(&self) { + registers::handle(|r| { + r.operational + .dcbaap + .update_volatile(|dcbaap| dcbaap.set(self.0.as_ptr() as u64)); + }) } } @@ -36,10 +39,12 @@ impl RawDCBAA { } } -fn number_of_slots(regs: &Registers) -> usize { - regs.capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() as usize - + 1_usize +fn number_of_slots() -> usize { + registers::handle(|r| { + r.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() as usize + + 1_usize + }) } diff --git a/test/src/event.rs b/test/src/event.rs index 982c5a03..88c0c1ed 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -1,10 +1,11 @@ -use crate::registers::Registers; use alloc::boxed::Box; use alloc::{vec, vec::Vec}; use bit_field::BitField; use xhci::ring::trb::event; use xhci::ring::trb::{self, event::CommandCompletion}; +use crate::registers; + const NUM_OF_TRBS_IN_RING: usize = 16; pub struct EventHandler { @@ -21,8 +22,8 @@ pub struct EventHandler { cycle_bit: bool, } impl EventHandler { - pub fn new(regs: &mut Registers) -> Self { - let number_of_rings = number_of_rings(regs); + pub fn new() -> Self { + let number_of_rings = number_of_rings(); let mut v = Self { segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings.into()], @@ -35,7 +36,7 @@ impl EventHandler { cycle_bit: true, }; - v.init(regs); + v.init(); v } @@ -58,8 +59,8 @@ impl EventHandler { assert!(self.handlers.is_empty(), "Some commands are not completed"); } - fn init(&mut self, regs: &mut Registers) { - EventHandlerInitializer::new(self, regs).init(); + fn init(&mut self) { + EventHandlerInitializer::new(self).init(); } fn dequeue_and_process(&mut self) { @@ -115,11 +116,10 @@ impl EventHandler { struct EventHandlerInitializer<'a> { handler: &'a mut EventHandler, - regs: &'a mut Registers, } impl<'a> EventHandlerInitializer<'a> { - fn new(handler: &'a mut EventHandler, regs: &'a mut Registers) -> Self { - Self { handler, regs } + fn new(handler: &'a mut EventHandler) -> Self { + Self { handler } } fn init(&mut self) { @@ -131,13 +131,14 @@ impl<'a> EventHandlerInitializer<'a> { } fn register_dequeue_pointer(&mut self) { - self.regs - .interrupter_register_set - .interrupter_mut(0) - .erdp - .update_volatile(|erdp| { - erdp.set_event_ring_dequeue_pointer(self.handler.next_trb_addr()) - }) + registers::handle(|r| { + r.interrupter_register_set + .interrupter_mut(0) + .erdp + .update_volatile(|erdp| { + erdp.set_event_ring_dequeue_pointer(self.handler.next_trb_addr()) + }) + }) } fn write_rings_addresses_in_table(&mut self) { @@ -151,31 +152,34 @@ impl<'a> EventHandlerInitializer<'a> { // We use polling for simplicity. fn disable_interrupts(&mut self) { - self.regs - .interrupter_register_set - .interrupter_mut(0) - .iman - .update_volatile(|iman| { - iman.clear_interrupt_enable(); - }) + registers::handle(|r| { + r.interrupter_register_set + .interrupter_mut(0) + .iman + .update_volatile(|iman| { + iman.clear_interrupt_enable(); + }) + }) } fn register_table_size(&mut self) { - self.regs - .interrupter_register_set - .interrupter_mut(0) - .erstsz - .update_volatile(|erstsz| { - erstsz.set(self.handler.segment_table.len() as u16); - }) + registers::handle(|r| { + r.interrupter_register_set + .interrupter_mut(0) + .erstsz + .update_volatile(|erstsz| { + erstsz.set(self.handler.segment_table.len() as u16); + }) + }) } fn enable_event_ring(&mut self) { - self.regs - .interrupter_register_set - .interrupter_mut(0) - .erstba - .update_volatile(|erstba| erstba.set(self.handler.segment_table.as_ptr() as u64)) + registers::handle(|r| { + r.interrupter_register_set + .interrupter_mut(0) + .erstba + .update_volatile(|erstba| erstba.set(self.handler.segment_table.as_ptr() as u64)) + }) } } @@ -203,9 +207,11 @@ impl EventRing { } } -fn number_of_rings(regs: &Registers) -> u16 { - regs.capability - .hcsparams2 - .read_volatile() - .event_ring_segment_table_max() +fn number_of_rings() -> u16 { + registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .event_ring_segment_table_max() + }) } diff --git a/test/src/main.rs b/test/src/main.rs index 8d4bd8fb..afeda976 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -15,8 +15,6 @@ mod scratchpat; mod transfer_ring; mod xhc; -use alloc::rc::Rc; -use core::cell::RefCell; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; @@ -27,11 +25,9 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> let (_, memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); allocator::init(memory_map); - // SAFETY: We are calling `get_accessor()` only once. - let regs = unsafe { registers::get_accessor() }; - let regs = Rc::new(RefCell::new(regs)); + registers::init(); - let (event_handler, command_ring, dcbaa) = xhc::init(®s); + let (event_handler, command_ring, dcbaa) = xhc::init(); let nop_addr = command_ring.borrow_mut().send_nop(); event_handler.borrow_mut().register_handler(nop_addr, |c| { @@ -42,7 +38,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> ); }); - ports::init_all_ports(regs, event_handler.clone(), command_ring, dcbaa); + ports::init_all_ports(event_handler.clone(), command_ring, dcbaa); event_handler.borrow_mut().process_trbs(); event_handler.borrow_mut().assert_all_commands_completed(); diff --git a/test/src/ports/context.rs b/test/src/ports/context.rs index adb1d8ca..cabd5455 100644 --- a/test/src/ports/context.rs +++ b/test/src/ports/context.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use crate::registers::Registers; +use crate::registers; use { alloc::boxed::Box, @@ -15,10 +15,10 @@ pub struct Context { pub output: Box, } impl Context { - pub fn new(regs: &Registers) -> Self { + pub fn new() -> Self { Self { - input: Input::new(regs), - output: Device::new(regs).into(), + input: Input::new(), + output: Device::new().into(), } } } @@ -49,8 +49,8 @@ impl Input { } } - fn new(regs: &Registers) -> Self { - if csz(regs) { + fn new() -> Self { + if csz() { Self::Byte64(Input64Byte::default().into()) } else { Self::Byte32(Input32Byte::default().into()) @@ -63,8 +63,8 @@ pub enum Device { Byte32(Box), } impl Device { - fn new(regs: &Registers) -> Self { - if csz(regs) { + fn new() -> Self { + if csz() { Self::Byte64(Device64Byte::default().into()) } else { Self::Byte32(Device32Byte::default().into()) @@ -72,6 +72,6 @@ impl Device { } } -fn csz(regs: &Registers) -> bool { - regs.capability.hccparams1.read_volatile().context_size() +fn csz() -> bool { + registers::handle(|r| r.capability.hccparams1.read_volatile().context_size()) } diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 52592c22..051fe6f7 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -3,7 +3,7 @@ mod context; use self::context::Context; use crate::{ command_ring::CommandRingController, dcbaa::DeviceContextBaseAddressArray, event::EventHandler, - registers::Registers, transfer_ring::TransferRingController, + registers, transfer_ring::TransferRingController, }; use alloc::rc::Rc; use core::cell::RefCell; @@ -11,41 +11,35 @@ use qemu_print::qemu_println; use xhci::{context::EndpointType, registers::PortRegisterSet}; pub fn init_all_ports( - regs: Rc>, event_handler: Rc>, cmd: Rc>, dcbaa: Rc>, ) { - let num_ports = num_ports(®s.borrow()); + let num_ports = num_ports(); for port in 0..num_ports { - if connected(®s.borrow(), port) { - init_port( - regs.clone(), - event_handler.clone(), - cmd.clone(), - dcbaa.clone(), - port, - ); + if connected(port) { + init_port(event_handler.clone(), cmd.clone(), dcbaa.clone(), port); } } } -fn connected(regs: &Registers, port: u8) -> bool { - regs.port_register_set - .read_volatile_at(port.into()) - .portsc - .current_connect_status() +fn connected(port: u8) -> bool { + registers::handle(|r| { + r.port_register_set + .read_volatile_at(port.into()) + .portsc + .current_connect_status() + }) } fn init_port( - regs: Rc>, event_handler: Rc>, cmd: Rc>, dcbaa: Rc>, port: u8, ) { - Resetter::new(&mut regs.borrow_mut(), port).reset(); + Resetter::new(port).reset(); let addr = cmd.borrow_mut().send_enable_slot(); @@ -62,29 +56,28 @@ fn init_port( qemu_println!("Slot enabled."); StructureInitializer::new( - regs.clone(), port, c.slot_id(), dcbaa, cmd.clone(), event_handler.clone(), - Context::new(®s.borrow()), + Context::new(), ) .create() }); } -fn num_ports(regs: &Registers) -> u8 { - regs.capability.hcsparams1.read_volatile().number_of_ports() +fn num_ports() -> u8 { + registers::handle(|r| r.capability.hcsparams1.read_volatile().number_of_ports()) } -struct Resetter<'a> { - regs: PortRegisterHandler<'a>, +struct Resetter { + regs: PortRegisterHandler, } -impl<'a> Resetter<'a> { - fn new(regs: &'a mut Registers, port_number: u8) -> Self { +impl Resetter { + fn new(port_number: u8) -> Self { Self { - regs: PortRegisterHandler::new(regs, port_number), + regs: PortRegisterHandler::new(port_number), } } @@ -109,21 +102,15 @@ impl<'a> Resetter<'a> { } struct SlotEnabler { - regs: Rc>, event_handler: Rc>, cmd: Rc>, } impl SlotEnabler { fn new( - regs: Rc>, event_handler: Rc>, cmd: Rc>, ) -> Self { - Self { - regs, - event_handler, - cmd, - } + Self { event_handler, cmd } } fn enable(&mut self) -> u64 { @@ -132,7 +119,6 @@ impl SlotEnabler { } struct StructureInitializer { - regs: Rc>, port: u8, slot: u8, dcbaa: Rc>, @@ -143,7 +129,6 @@ struct StructureInitializer { } impl StructureInitializer { fn new( - regs: Rc>, port: u8, slot: u8, dcbaa: Rc>, @@ -152,7 +137,6 @@ impl StructureInitializer { cx: Context, ) -> Self { Self { - regs, port, slot, dcbaa, @@ -179,7 +163,7 @@ impl StructureInitializer { &mut self.cx, self.port, &self.ring, - PortRegisterHandler::new(&mut self.regs.borrow_mut(), self.port), + PortRegisterHandler::new(self.port), ) .init(); } @@ -230,14 +214,14 @@ struct Ep0ContextInitializer<'a> { cx: &'a mut Context, port: u8, ring: &'a TransferRingController, - regs: PortRegisterHandler<'a>, + regs: PortRegisterHandler, } impl<'a> Ep0ContextInitializer<'a> { fn new( cx: &'a mut Context, port: u8, ring: &'a TransferRingController, - regs: PortRegisterHandler<'a>, + regs: PortRegisterHandler, ) -> Self { Self { cx, @@ -269,27 +253,28 @@ impl<'a> Ep0ContextInitializer<'a> { } } -struct PortRegisterHandler<'a> { - regs: &'a mut Registers, +struct PortRegisterHandler { port_number: u8, } -impl<'a> PortRegisterHandler<'a> { - fn new(regs: &'a mut Registers, port_number: u8) -> Self { - Self { regs, port_number } +impl PortRegisterHandler { + fn new(port_number: u8) -> Self { + Self { port_number } } fn read(&self) -> PortRegisterSet { - self.regs - .port_register_set - .read_volatile_at(self.port_number.into()) + registers::handle(|r| { + r.port_register_set + .read_volatile_at(self.port_number.into()) + }) } fn update(&mut self, f: T) where T: FnOnce(&mut PortRegisterSet), { - self.regs - .port_register_set - .update_volatile_at(self.port_number.into(), f) + registers::handle(|r| { + r.port_register_set + .update_volatile_at(self.port_number.into(), f) + }) } } diff --git a/test/src/registers.rs b/test/src/registers.rs index b2f8ac58..2b656abf 100644 --- a/test/src/registers.rs +++ b/test/src/registers.rs @@ -1,13 +1,12 @@ -use bit_field::BitField; - use crate::mapper::Mapper; +use bit_field::BitField; +use conquer_once::spin::OnceCell; +use spinning_top::Spinlock; +use xhci::Registers; -pub type Registers = xhci::Registers; +static REGISTERS: OnceCell>> = OnceCell::uninit(); -/// # Safety -/// -/// Multiple returned values must not exist in the same scope. -pub unsafe fn get_accessor() -> Registers { +pub fn init() { let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); // See [1] for the structure of base address registers. @@ -25,6 +24,19 @@ pub unsafe fn get_accessor() -> Registers { let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; - // SAFETY: The caller ensures only one instance is created in a scope. - unsafe { xhci::Registers::new(mmio_base, Mapper) } + REGISTERS.init_once(|| + // SAFETY: The function will be called only once. + unsafe { Spinlock::new(xhci::Registers::new(mmio_base, Mapper) )}); +} + +// This function receives a closure instead of returning a lock guard to reduce +// the possibility of deadlocks. +pub fn handle(f: impl FnOnce(&mut Registers) -> T) -> T { + let mut regs = REGISTERS + .try_get() + .expect("xHC not initialized") + .try_lock() + .expect("xHC is already locked"); + + f(&mut regs) } diff --git a/test/src/scratchpat.rs b/test/src/scratchpat.rs index 0c14f1f4..fb0ca3c2 100644 --- a/test/src/scratchpat.rs +++ b/test/src/scratchpat.rs @@ -1,11 +1,12 @@ -use crate::registers::Registers; +use crate::registers; -pub fn init(regs: &Registers) { - let num_of_buffers = regs - .capability - .hcsparams2 - .read_volatile() - .max_scratchpad_buffers(); +pub fn init() { + let num_of_buffers = registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .max_scratchpad_buffers() + }); if num_of_buffers > 0 { todo!("Implement scratchpad buffer initialization"); diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 0ac241fa..c10e7d71 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,111 +1,113 @@ use crate::command_ring::CommandRingController; use crate::dcbaa::DeviceContextBaseAddressArray; use crate::event::EventHandler; -use crate::mapper::Mapper; -use crate::registers::Registers; +use crate::registers; use crate::scratchpat; use alloc::rc::Rc; use core::cell::RefCell; use qemu_print::qemu_println; -use xhci::registers::operational::UsbStatusRegister; -use xhci::registers::Operational; /// Initializes the host controller according to 4.2 of xHCI spec. /// /// Note that we do not enable interrupts as it is optional and for simplicity. -pub fn init( - regs: &Rc>, -) -> ( +pub fn init() -> ( Rc>, Rc>, Rc>, ) { qemu_println!("Initializing xHC..."); - wait_until_controller_is_ready(®s.borrow()); - stop(&mut regs.borrow_mut()); - reset(&mut regs.borrow_mut()); - set_num_of_enabled_slots(&mut regs.borrow_mut()); + wait_until_controller_is_ready(); + stop(); + reset(); + set_num_of_enabled_slots(); - let event_handler = EventHandler::new(&mut regs.borrow_mut()); + let event_handler = EventHandler::new(); let event_handler = Rc::new(RefCell::new(event_handler)); - let command_ring = CommandRingController::new(®s); + let command_ring = CommandRingController::new(); let command_ring = Rc::new(RefCell::new(command_ring)); - let dcbaa = DeviceContextBaseAddressArray::new(&mut regs.borrow_mut()); + let dcbaa = DeviceContextBaseAddressArray::new(); let dcbaa = Rc::new(RefCell::new(dcbaa)); - scratchpat::init(®s.borrow()); + scratchpat::init(); - run(&mut regs.borrow_mut().operational); - ensure_no_error_occurs(®s.borrow().operational.usbsts.read_volatile()); + run(); + ensure_no_error_occurs(); qemu_println!("xHC is initialized."); (event_handler, command_ring, dcbaa) } -fn run(op: &mut Operational) { - op.usbcmd.update_volatile(|u| { - u.set_run_stop(); - }); +fn run() { + registers::handle(|r| { + let op = &mut r.operational; - while op.usbsts.read_volatile().hc_halted() {} -} + op.usbcmd.update_volatile(|u| { + u.set_run_stop(); + }); -fn ensure_no_error_occurs(s: &UsbStatusRegister) { - assert!(!s.hc_halted(), "HC is halted."); - assert!( - !s.host_system_error(), - "An error occured on the host system." - ); - assert!(!s.host_controller_error(), "An error occured on the xHC."); + while op.usbsts.read_volatile().hc_halted() {} + }); } -fn wait_until_controller_is_ready(regs: &Registers) { - while regs - .operational - .usbsts - .read_volatile() - .controller_not_ready() - {} +fn ensure_no_error_occurs() { + registers::handle(|r| { + let s = r.operational.usbsts.read_volatile(); + + assert!(!s.hc_halted(), "HC is halted."); + assert!( + !s.host_system_error(), + "An error occured on the host system." + ); + assert!(!s.host_controller_error(), "An error occured on the xHC."); + }) } -fn stop(regs: &mut Registers) { - Stopper::new(&mut regs.operational).stop(); +fn wait_until_controller_is_ready() { + registers::handle( + |r| { + while r.operational.usbsts.read_volatile().controller_not_ready() {} + }, + ); } -fn reset(regs: &mut Registers) { - Resetter::new(&mut regs.operational).reset(); +fn stop() { + Stopper::new().stop(); } -fn set_num_of_enabled_slots(regs: &mut Registers) { - SlotNumberSetter::new(regs).set(); +fn reset() { + Resetter::new().reset(); } -struct Stopper<'a> { - op: &'a mut Operational, +fn set_num_of_enabled_slots() { + SlotNumberSetter::new().set(); } -impl<'a> Stopper<'a> { - fn new(op: &'a mut Operational) -> Self { - Self { op } + +struct Stopper {} +impl Stopper { + fn new() -> Self { + Self {} } fn stop(&mut self) { - self.op.usbcmd.update_volatile(|u| { - u.clear_run_stop(); - }); + registers::handle(|r| { + let op = &mut r.operational; + + op.usbcmd.update_volatile(|u| { + u.clear_run_stop(); + }); - while !self.op.usbsts.read_volatile().hc_halted() {} + while !op.usbsts.read_volatile().hc_halted() {} + }) } } -struct Resetter<'a> { - op: &'a mut Operational, -} -impl<'a> Resetter<'a> { - fn new(op: &'a mut Operational) -> Self { - Self { op } +struct Resetter {} +impl Resetter { + fn new() -> Self { + Self {} } fn reset(&mut self) { @@ -115,41 +117,52 @@ impl<'a> Resetter<'a> { } fn start_resetting(&mut self) { - self.op.usbcmd.update_volatile(|u| { - u.set_host_controller_reset(); - }); + registers::handle(|r| { + r.operational.usbcmd.update_volatile(|u| { + u.set_host_controller_reset(); + }); + }) } fn wait_until_reset_completed(&self) { - while self.op.usbcmd.read_volatile().host_controller_reset() {} + registers::handle( + |r| { + while r.operational.usbcmd.read_volatile().host_controller_reset() {} + }, + ) } fn wait_until_ready(&self) { - while self.op.usbsts.read_volatile().controller_not_ready() {} + registers::handle( + |r| { + while r.operational.usbsts.read_volatile().controller_not_ready() {} + }, + ) } } -struct SlotNumberSetter<'a> { - regs: &'a mut Registers, -} -impl<'a> SlotNumberSetter<'a> { - fn new(regs: &'a mut Registers) -> Self { - Self { regs } +struct SlotNumberSetter {} +impl SlotNumberSetter { + fn new() -> Self { + Self {} } fn set(&mut self) { let n = self.number_of_slots(); - self.regs.operational.config.update_volatile(|c| { - c.set_max_device_slots_enabled(n); - }); + registers::handle(|r| { + r.operational.config.update_volatile(|c| { + c.set_max_device_slots_enabled(n); + }); + }) } fn number_of_slots(&self) -> u8 { - self.regs - .capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() + registers::handle(|r| { + r.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() + }) } } From d1ab860cabfc4641d784f4d3056fe42dfeb8aab7 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 22:58:45 +0900 Subject: [PATCH 079/115] Static command --- test/src/command_ring.rs | 46 +++++++++++++++++++++++++++++++--------- test/src/main.rs | 6 +++--- test/src/ports/mod.rs | 28 +++++++----------------- test/src/xhc.rs | 8 +++---- 4 files changed, 50 insertions(+), 38 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 483cb534..49901e2d 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,28 +1,54 @@ +use crate::registers; use alloc::boxed::Box; +use conquer_once::spin::OnceCell; +use core::ops::DerefMut; +use spinning_top::Spinlock; use xhci::ring::trb::{self, command}; -use crate::registers; - const NUM_OF_TRBS_IN_RING: usize = 16; -pub struct CommandRingController { +static COMMAND_RING_CONTROLLER: OnceCell> = OnceCell::uninit(); + +pub fn init() { + COMMAND_RING_CONTROLLER.init_once(|| Spinlock::new(CommandRingController::new())); + + lock().init(); +} + +pub fn send_nop() -> u64 { + lock().send_nop() +} + +pub fn send_enable_slot() -> u64 { + lock().send_enable_slot() +} + +pub fn send_address_device(input_cx_addr: u64, slot: u8) -> u64 { + lock().send_address_device(input_cx_addr, slot) +} + +fn lock() -> impl DerefMut { + COMMAND_RING_CONTROLLER + .try_get() + .expect("Command ring controller not initialized") + .try_lock() + .expect("Command ring controller is already locked") +} + +struct CommandRingController { ring: Box, enqueue_ptr: usize, cycle_bit: bool, } impl CommandRingController { - pub fn new() -> Self { - let mut v = Self { + fn new() -> Self { + Self { ring: Box::new(CommandRing::new()), enqueue_ptr: 0, cycle_bit: true, - }; - - v.init(); - - v + } } pub fn send_nop(&mut self) -> u64 { diff --git a/test/src/main.rs b/test/src/main.rs index afeda976..68f7b23c 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -27,9 +27,9 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> registers::init(); - let (event_handler, command_ring, dcbaa) = xhc::init(); + let (event_handler, dcbaa) = xhc::init(); - let nop_addr = command_ring.borrow_mut().send_nop(); + let nop_addr = command_ring::send_nop(); event_handler.borrow_mut().register_handler(nop_addr, |c| { assert_eq!( c.completion_code(), @@ -38,7 +38,7 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> ); }); - ports::init_all_ports(event_handler.clone(), command_ring, dcbaa); + ports::init_all_ports(event_handler.clone(), dcbaa); event_handler.borrow_mut().process_trbs(); event_handler.borrow_mut().assert_all_commands_completed(); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 051fe6f7..206e8198 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -2,8 +2,8 @@ mod context; use self::context::Context; use crate::{ - command_ring::CommandRingController, dcbaa::DeviceContextBaseAddressArray, event::EventHandler, - registers, transfer_ring::TransferRingController, + command_ring, dcbaa::DeviceContextBaseAddressArray, event::EventHandler, registers, + transfer_ring::TransferRingController, }; use alloc::rc::Rc; use core::cell::RefCell; @@ -12,14 +12,13 @@ use xhci::{context::EndpointType, registers::PortRegisterSet}; pub fn init_all_ports( event_handler: Rc>, - cmd: Rc>, dcbaa: Rc>, ) { let num_ports = num_ports(); for port in 0..num_ports { if connected(port) { - init_port(event_handler.clone(), cmd.clone(), dcbaa.clone(), port); + init_port(event_handler.clone(), dcbaa.clone(), port); } } } @@ -35,13 +34,12 @@ fn connected(port: u8) -> bool { fn init_port( event_handler: Rc>, - cmd: Rc>, dcbaa: Rc>, port: u8, ) { Resetter::new(port).reset(); - let addr = cmd.borrow_mut().send_enable_slot(); + let addr = command_ring::send_enable_slot(); event_handler .clone() @@ -59,7 +57,6 @@ fn init_port( port, c.slot_id(), dcbaa, - cmd.clone(), event_handler.clone(), Context::new(), ) @@ -103,18 +100,14 @@ impl Resetter { struct SlotEnabler { event_handler: Rc>, - cmd: Rc>, } impl SlotEnabler { - fn new( - event_handler: Rc>, - cmd: Rc>, - ) -> Self { - Self { event_handler, cmd } + fn new(event_handler: Rc>) -> Self { + Self { event_handler } } fn enable(&mut self) -> u64 { - self.cmd.borrow_mut().send_enable_slot() + command_ring::send_enable_slot() } } @@ -122,7 +115,6 @@ struct StructureInitializer { port: u8, slot: u8, dcbaa: Rc>, - cmd: Rc>, event_handler: Rc>, ring: TransferRingController, cx: Context, @@ -132,7 +124,6 @@ impl StructureInitializer { port: u8, slot: u8, dcbaa: Rc>, - cmd: Rc>, event_handler: Rc>, cx: Context, ) -> Self { @@ -140,7 +131,6 @@ impl StructureInitializer { port, slot, dcbaa, - cmd, event_handler, ring: TransferRingController::new(), cx, @@ -175,9 +165,7 @@ impl StructureInitializer { } fn issue_address_device_command(&mut self) { - self.cmd - .borrow_mut() - .send_address_device(self.cx.input.phys_addr(), self.slot); + command_ring::send_address_device(self.cx.input.phys_addr(), self.slot); } } diff --git a/test/src/xhc.rs b/test/src/xhc.rs index c10e7d71..6346a245 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,4 +1,4 @@ -use crate::command_ring::CommandRingController; +use crate::command_ring; use crate::dcbaa::DeviceContextBaseAddressArray; use crate::event::EventHandler; use crate::registers; @@ -12,7 +12,6 @@ use qemu_print::qemu_println; /// Note that we do not enable interrupts as it is optional and for simplicity. pub fn init() -> ( Rc>, - Rc>, Rc>, ) { qemu_println!("Initializing xHC..."); @@ -25,8 +24,7 @@ pub fn init() -> ( let event_handler = EventHandler::new(); let event_handler = Rc::new(RefCell::new(event_handler)); - let command_ring = CommandRingController::new(); - let command_ring = Rc::new(RefCell::new(command_ring)); + command_ring::init(); let dcbaa = DeviceContextBaseAddressArray::new(); let dcbaa = Rc::new(RefCell::new(dcbaa)); @@ -37,7 +35,7 @@ pub fn init() -> ( qemu_println!("xHC is initialized."); - (event_handler, command_ring, dcbaa) + (event_handler, dcbaa) } fn run() { From b104a756b6f84906e850984993004c7787d1db66 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 23:28:34 +0900 Subject: [PATCH 080/115] Static event --- test/src/event.rs | 78 +++++++++++++++++-------------------------- test/src/main.rs | 17 ++-------- test/src/ports/mod.rs | 49 ++++----------------------- test/src/xhc.rs | 13 +++----- 4 files changed, 44 insertions(+), 113 deletions(-) diff --git a/test/src/event.rs b/test/src/event.rs index 88c0c1ed..c3a11c00 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -1,87 +1,69 @@ -use alloc::boxed::Box; +use crate::registers; use alloc::{vec, vec::Vec}; use bit_field::BitField; +use conquer_once::spin::OnceCell; +use core::ops::DerefMut; +use spinning_top::Spinlock; use xhci::ring::trb::event; -use xhci::ring::trb::{self, event::CommandCompletion}; - -use crate::registers; +use xhci::ring::trb::{self}; const NUM_OF_TRBS_IN_RING: usize = 16; -pub struct EventHandler { +static EVENT_HANDLER: OnceCell> = OnceCell::uninit(); + +pub fn init() { + EVENT_HANDLER.init_once(|| Spinlock::new(EventHandler::new())); + + lock().init(); +} + +fn lock() -> impl DerefMut { + EVENT_HANDLER + .try_get() + .expect("Event handler not initialized") + .try_lock() + .expect("Event handler is already locked") +} + +struct EventHandler { segment_table: Vec, rings: Vec, - // Alas, we cannot use `HashMap` because it's not in `alloc` yet. - // See https://github.com/rust-lang/rust/issues/27242. - handlers: Vec<(u64, Box)>, - dequeue_ptr_segment: u64, dequeue_ptr_ring: u64, cycle_bit: bool, } impl EventHandler { - pub fn new() -> Self { + fn new() -> Self { let number_of_rings = number_of_rings(); - let mut v = Self { + Self { segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings.into()], rings: vec![EventRing::new(); number_of_rings.into()], - handlers: Vec::new(), dequeue_ptr_segment: 0, dequeue_ptr_ring: 0, cycle_bit: true, - }; - - v.init(); - - v - } - - pub fn register_handler<'a>( - &mut self, - trb_addr: u64, - handler: impl FnOnce(CommandCompletion) + 'static, - ) { - self.handlers.push((trb_addr, Box::new(handler))); - } - - pub fn process_trbs(&mut self) { - while !self.ring_is_empty() { - self.dequeue_and_process(); } } - pub fn assert_all_commands_completed(&self) { - assert!(self.handlers.is_empty(), "Some commands are not completed"); - } - fn init(&mut self) { EventHandlerInitializer::new(self).init(); } - fn dequeue_and_process(&mut self) { - assert!(!self.ring_is_empty()); + pub fn dequeue(&mut self) -> Option> { + if self.ring_is_empty() { + return None; + } let t = self.rings[self.dequeue_ptr_segment as usize].0[self.dequeue_ptr_ring as usize]; let t = event::Allowed::try_from(t); - if let Ok(event::Allowed::CommandCompletion(t)) = t { - let idx = self - .handlers - .iter() - .position(|(trb_addr, _)| *trb_addr == t.command_trb_pointer()) - .unwrap_or_else(|| panic!("No handler for {:?}", t)); - - let (_, handler) = self.handlers.remove(idx); - - handler(t); - } - self.increment_ptr(); + + Some(t) } fn increment_ptr(&mut self) { diff --git a/test/src/main.rs b/test/src/main.rs index 68f7b23c..8f81b280 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -18,7 +18,6 @@ mod xhc; use qemu_exit::QEMUExit; use qemu_print::qemu_println; use uefi::table::boot::MemoryType; -use xhci::ring::trb::event::CompletionCode; #[uefi::entry] fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { @@ -27,21 +26,11 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> registers::init(); - let (event_handler, dcbaa) = xhc::init(); + let dcbaa = xhc::init(); let nop_addr = command_ring::send_nop(); - event_handler.borrow_mut().register_handler(nop_addr, |c| { - assert_eq!( - c.completion_code(), - Ok(CompletionCode::Success), - "NOP failed." - ); - }); - - ports::init_all_ports(event_handler.clone(), dcbaa); - - event_handler.borrow_mut().process_trbs(); - event_handler.borrow_mut().assert_all_commands_completed(); + + ports::init_all_ports(dcbaa); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 206e8198..97f8a746 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -2,23 +2,19 @@ mod context; use self::context::Context; use crate::{ - command_ring, dcbaa::DeviceContextBaseAddressArray, event::EventHandler, registers, + command_ring, dcbaa::DeviceContextBaseAddressArray, registers, transfer_ring::TransferRingController, }; use alloc::rc::Rc; use core::cell::RefCell; -use qemu_print::qemu_println; use xhci::{context::EndpointType, registers::PortRegisterSet}; -pub fn init_all_ports( - event_handler: Rc>, - dcbaa: Rc>, -) { +pub fn init_all_ports(dcbaa: Rc>) { let num_ports = num_ports(); for port in 0..num_ports { if connected(port) { - init_port(event_handler.clone(), dcbaa.clone(), port); + init_port(dcbaa.clone(), port); } } } @@ -32,36 +28,10 @@ fn connected(port: u8) -> bool { }) } -fn init_port( - event_handler: Rc>, - dcbaa: Rc>, - port: u8, -) { +fn init_port(dcbaa: Rc>, port: u8) { Resetter::new(port).reset(); let addr = command_ring::send_enable_slot(); - - event_handler - .clone() - .borrow_mut() - .register_handler(addr, move |c| { - assert_eq!( - c.completion_code(), - Ok(xhci::ring::trb::event::CompletionCode::Success), - "Enable slot failed." - ); - - qemu_println!("Slot enabled."); - - StructureInitializer::new( - port, - c.slot_id(), - dcbaa, - event_handler.clone(), - Context::new(), - ) - .create() - }); } fn num_ports() -> u8 { @@ -98,12 +68,10 @@ impl Resetter { } } -struct SlotEnabler { - event_handler: Rc>, -} +struct SlotEnabler {} impl SlotEnabler { - fn new(event_handler: Rc>) -> Self { - Self { event_handler } + fn new() -> Self { + Self {} } fn enable(&mut self) -> u64 { @@ -115,7 +83,6 @@ struct StructureInitializer { port: u8, slot: u8, dcbaa: Rc>, - event_handler: Rc>, ring: TransferRingController, cx: Context, } @@ -124,14 +91,12 @@ impl StructureInitializer { port: u8, slot: u8, dcbaa: Rc>, - event_handler: Rc>, cx: Context, ) -> Self { Self { port, slot, dcbaa, - event_handler, ring: TransferRingController::new(), cx, } diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 6346a245..beacd9d9 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,6 +1,6 @@ use crate::command_ring; use crate::dcbaa::DeviceContextBaseAddressArray; -use crate::event::EventHandler; +use crate::event; use crate::registers; use crate::scratchpat; use alloc::rc::Rc; @@ -10,10 +10,7 @@ use qemu_print::qemu_println; /// Initializes the host controller according to 4.2 of xHCI spec. /// /// Note that we do not enable interrupts as it is optional and for simplicity. -pub fn init() -> ( - Rc>, - Rc>, -) { +pub fn init() -> Rc> { qemu_println!("Initializing xHC..."); wait_until_controller_is_ready(); @@ -21,9 +18,7 @@ pub fn init() -> ( reset(); set_num_of_enabled_slots(); - let event_handler = EventHandler::new(); - let event_handler = Rc::new(RefCell::new(event_handler)); - + event::init(); command_ring::init(); let dcbaa = DeviceContextBaseAddressArray::new(); @@ -35,7 +30,7 @@ pub fn init() -> ( qemu_println!("xHC is initialized."); - (event_handler, dcbaa) + dcbaa } fn run() { From 1908ee41c9fb70534dc41d47458790efd54b62a1 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 18 Dec 2023 23:31:24 +0900 Subject: [PATCH 081/115] Static --- test/src/dcbaa.rs | 33 +++++++++++++++++++++++++-------- test/src/main.rs | 4 ++-- test/src/ports/mod.rs | 27 +++++++-------------------- test/src/xhc.rs | 12 +++--------- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs index 5e3830e2..f3c31562 100644 --- a/test/src/dcbaa.rs +++ b/test/src/dcbaa.rs @@ -1,19 +1,36 @@ +use crate::registers; use alloc::vec; use alloc::vec::Vec; +use conquer_once::spin::OnceCell; +use spinning_top::Spinlock; -use crate::registers; +static DCBAA: OnceCell> = OnceCell::uninit(); -pub struct DeviceContextBaseAddressArray(Vec); -impl DeviceContextBaseAddressArray { - pub fn new() -> Self { - let mut v = Self(vec![RawDCBAA::new(); number_of_slots()]); +pub fn init() { + DCBAA.init_once(|| Spinlock::new(DeviceContextBaseAddressArray::new())); + + lock().init(); +} - v.init(); +pub fn register_address(port: u8, addr: u64) { + lock().register_address(port, addr); +} + +fn lock() -> impl core::ops::DerefMut { + DCBAA + .try_get() + .expect("Device context base address array not initialized") + .try_lock() + .expect("Device context base address array is already locked") +} - v +struct DeviceContextBaseAddressArray(Vec); +impl DeviceContextBaseAddressArray { + fn new() -> Self { + Self(vec![RawDCBAA::new(); number_of_slots()]) } - pub fn register_address(&mut self, port: u8, addr: u64) { + fn register_address(&mut self, port: u8, addr: u64) { self.0[port as usize].0 = addr; } diff --git a/test/src/main.rs b/test/src/main.rs index 8f81b280..12d4aafa 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -26,11 +26,11 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> registers::init(); - let dcbaa = xhc::init(); + xhc::init(); let nop_addr = command_ring::send_nop(); - ports::init_all_ports(dcbaa); + ports::init_all_ports(); let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 97f8a746..20a32551 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -1,20 +1,16 @@ mod context; use self::context::Context; -use crate::{ - command_ring, dcbaa::DeviceContextBaseAddressArray, registers, - transfer_ring::TransferRingController, -}; -use alloc::rc::Rc; -use core::cell::RefCell; +use crate::dcbaa; +use crate::{command_ring, registers, transfer_ring::TransferRingController}; use xhci::{context::EndpointType, registers::PortRegisterSet}; -pub fn init_all_ports(dcbaa: Rc>) { +pub fn init_all_ports() { let num_ports = num_ports(); for port in 0..num_ports { if connected(port) { - init_port(dcbaa.clone(), port); + init_port(port); } } } @@ -28,7 +24,7 @@ fn connected(port: u8) -> bool { }) } -fn init_port(dcbaa: Rc>, port: u8) { +fn init_port(port: u8) { Resetter::new(port).reset(); let addr = command_ring::send_enable_slot(); @@ -82,21 +78,14 @@ impl SlotEnabler { struct StructureInitializer { port: u8, slot: u8, - dcbaa: Rc>, ring: TransferRingController, cx: Context, } impl StructureInitializer { - fn new( - port: u8, - slot: u8, - dcbaa: Rc>, - cx: Context, - ) -> Self { + fn new(port: u8, slot: u8, cx: Context) -> Self { Self { port, slot, - dcbaa, ring: TransferRingController::new(), cx, } @@ -124,9 +113,7 @@ impl StructureInitializer { } fn register_with_dcbaa(&mut self) { - self.dcbaa - .borrow_mut() - .register_address(self.slot, self.cx.input.phys_addr()); + dcbaa::register_address(self.port, self.cx.input.phys_addr()); } fn issue_address_device_command(&mut self) { diff --git a/test/src/xhc.rs b/test/src/xhc.rs index beacd9d9..ed8b2b99 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,16 +1,14 @@ use crate::command_ring; -use crate::dcbaa::DeviceContextBaseAddressArray; +use crate::dcbaa; use crate::event; use crate::registers; use crate::scratchpat; -use alloc::rc::Rc; -use core::cell::RefCell; use qemu_print::qemu_println; /// Initializes the host controller according to 4.2 of xHCI spec. /// /// Note that we do not enable interrupts as it is optional and for simplicity. -pub fn init() -> Rc> { +pub fn init() { qemu_println!("Initializing xHC..."); wait_until_controller_is_ready(); @@ -20,17 +18,13 @@ pub fn init() -> Rc> { event::init(); command_ring::init(); - - let dcbaa = DeviceContextBaseAddressArray::new(); - let dcbaa = Rc::new(RefCell::new(dcbaa)); + dcbaa::init(); scratchpat::init(); run(); ensure_no_error_occurs(); qemu_println!("xHC is initialized."); - - dcbaa } fn run() { From 93a5fb862da67ee5d883d853a317d3f8cdf5e916 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 09:51:28 +0900 Subject: [PATCH 082/115] Fix --- test/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index 48510579..54cd1715 100644 --- a/test/Makefile +++ b/test/Makefile @@ -31,7 +31,8 @@ $(IMG): $(EFI) build mmd -i $@ ::/efi/boot mcopy -i $@ $(EFI) ::/efi/boot/bootx64.efi -$(EFI): $(wildcard src/**/*.rs) Cargo.toml +$(EFI): $(shell find src/) Cargo.toml + echo $^ cargo build build: From bd053c4c69aa1c85bc20716e756d04077eeb175b Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 10:19:30 +0900 Subject: [PATCH 083/115] Doing --- test/src/command_ring.rs | 76 ++++++++++++++++++++++++++++++++-------- test/src/event.rs | 4 +++ test/src/main.rs | 12 +++++++ test/src/ports/mod.rs | 6 ++-- 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 49901e2d..41f893f9 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,9 +1,12 @@ use crate::registers; -use alloc::boxed::Box; +use alloc::{boxed::Box, vec::Vec}; use conquer_once::spin::OnceCell; -use core::ops::DerefMut; +use core::ops::{DerefMut, Index}; use spinning_top::Spinlock; -use xhci::ring::trb::{self, command}; +use xhci::ring::trb::{ + self, command, + event::{self, CommandCompletion, CompletionCode}, +}; const NUM_OF_TRBS_IN_RING: usize = 16; @@ -15,15 +18,23 @@ pub fn init() { lock().init(); } -pub fn send_nop() -> u64 { +pub fn assert_all_trbs_are_processed() { + lock().assert_all_trbs_are_processed(); +} + +pub fn process_trb(event_trb: &CommandCompletion) { + lock().process_trb(event_trb) +} + +pub fn send_nop() { lock().send_nop() } -pub fn send_enable_slot() -> u64 { +pub fn send_enable_slot() { lock().send_enable_slot() } -pub fn send_address_device(input_cx_addr: u64, slot: u8) -> u64 { +pub fn send_address_device(input_cx_addr: u64, slot: u8) { lock().send_address_device(input_cx_addr, slot) } @@ -38,6 +49,8 @@ fn lock() -> impl DerefMut { struct CommandRingController { ring: Box, + sent_trbs: Vec<(u64, command::Allowed)>, + enqueue_ptr: usize, cycle_bit: bool, } @@ -46,26 +59,54 @@ impl CommandRingController { Self { ring: Box::new(CommandRing::new()), + sent_trbs: Vec::new(), + enqueue_ptr: 0, cycle_bit: true, } } - pub fn send_nop(&mut self) -> u64 { + fn assert_all_trbs_are_processed(&self) { + assert!(self.sent_trbs.is_empty(), "Some TRBs are not processed"); + } + + fn process_trb(&mut self, event_trb: &CommandCompletion) { + let command_trb_idx = self + .sent_trbs + .iter() + .position(|(addr, _)| *addr == event_trb.command_trb_pointer()) + .expect("Command TRB not found"); + + let (_, command_trb) = self.sent_trbs.remove(command_trb_idx); + + assert_eq!( + event_trb.completion_code(), + Ok(CompletionCode::Success), + "Event TRB has an error code: {:?}", + event_trb.completion_code() + ); + + match command_trb { + command::Allowed::Noop(_) => {} + _ => panic!("Unexpected command TRB: {:?}", command_trb), + } + } + + fn send_nop(&mut self) { let trb = command::Noop::new(); let trb = command::Allowed::Noop(trb); self.enqueue(trb) } - pub fn send_enable_slot(&mut self) -> u64 { + fn send_enable_slot(&mut self) { let trb = command::EnableSlot::new(); let trb = command::Allowed::EnableSlot(trb); self.enqueue(trb) } - pub fn send_address_device(&mut self, input_cx_addr: u64, slot: u8) -> u64 { + fn send_address_device(&mut self, input_cx_addr: u64, slot: u8) { let trb = *command::AddressDevice::new() .set_input_context_pointer(input_cx_addr) .set_slot_id(slot); @@ -74,7 +115,7 @@ impl CommandRingController { self.enqueue(trb) } - fn enqueue<'a>(&'a mut self, trb: command::Allowed) -> u64 { + fn enqueue(&mut self, trb: command::Allowed) { Enqueuer::new(self).enqueue(trb) } @@ -96,15 +137,16 @@ impl<'a> Enqueuer<'a> { Self { controller } } - fn enqueue(&mut self, mut trb: command::Allowed) -> u64 { - let addr = self.written_trb_address(); - + fn enqueue(&mut self, mut trb: command::Allowed) { self.modify_cycle_bit(&mut trb); self.write_trb(trb); + + let a = self.written_trb_address(); + + self.store_trb(a, trb); + self.increment_enqueue_ptr(); self.notify_command_is_sent(); - - addr } fn enqueue_link(&mut self) { @@ -148,6 +190,10 @@ impl<'a> Enqueuer<'a> { }) } + fn store_trb(&mut self, addr: u64, trb: command::Allowed) { + self.controller.sent_trbs.push((addr, trb)); + } + fn can_enqueue_trbs(&self) -> bool { // -1 for the space for a link TRB. self.controller.enqueue_ptr < NUM_OF_TRBS_IN_RING - 1 diff --git a/test/src/event.rs b/test/src/event.rs index c3a11c00..1aa81ea5 100644 --- a/test/src/event.rs +++ b/test/src/event.rs @@ -17,6 +17,10 @@ pub fn init() { lock().init(); } +pub fn dequeue() -> Option> { + lock().dequeue() +} + fn lock() -> impl DerefMut { EVENT_HANDLER .try_get() diff --git a/test/src/main.rs b/test/src/main.rs index 12d4aafa..9f6b74b7 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -32,6 +32,18 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> ports::init_all_ports(); + while let Some(trb) = event::dequeue() { + match trb { + Ok(xhci::ring::trb::event::Allowed::CommandCompletion(x)) => { + command_ring::process_trb(&x); + } + Ok(x) => panic!("Unhandled TRB: {:?}", x), + Err(x) => panic!("Unknown TRB: {:?}", x), + } + } + + command_ring::assert_all_trbs_are_processed(); + let handler = qemu_exit::X86::new(0xf4, 33); handler.exit_success(); } diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 20a32551..602a23f9 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -27,7 +27,7 @@ fn connected(port: u8) -> bool { fn init_port(port: u8) { Resetter::new(port).reset(); - let addr = command_ring::send_enable_slot(); + command_ring::send_enable_slot(); } fn num_ports() -> u8 { @@ -70,8 +70,8 @@ impl SlotEnabler { Self {} } - fn enable(&mut self) -> u64 { - command_ring::send_enable_slot() + fn enable(&mut self) { + command_ring::send_enable_slot(); } } From 001b2c841ecc75fc3a2ce3f2d0922332bc05c1ef Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 11:16:45 +0900 Subject: [PATCH 084/115] Doing --- test/src/command_ring.rs | 56 ++++++++++++++++++++++++++++------------ test/src/main.rs | 3 +++ test/src/ports/mod.rs | 45 ++++++++++++++++++++++++++++---- 3 files changed, 82 insertions(+), 22 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 41f893f9..16398811 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -1,11 +1,12 @@ +use crate::ports; use crate::registers; use alloc::{boxed::Box, vec::Vec}; use conquer_once::spin::OnceCell; -use core::ops::{DerefMut, Index}; +use core::ops::DerefMut; use spinning_top::Spinlock; use xhci::ring::trb::{ self, command, - event::{self, CommandCompletion, CompletionCode}, + event::{CommandCompletion, CompletionCode}, }; const NUM_OF_TRBS_IN_RING: usize = 16; @@ -15,35 +16,59 @@ static COMMAND_RING_CONTROLLER: OnceCell> = Once pub fn init() { COMMAND_RING_CONTROLLER.init_once(|| Spinlock::new(CommandRingController::new())); - lock().init(); + try_lock() + .expect("Failed to lock command ring controller") + .init(); } pub fn assert_all_trbs_are_processed() { - lock().assert_all_trbs_are_processed(); + try_lock() + .expect("Failed to lock command ring controller") + .assert_all_trbs_are_processed() } pub fn process_trb(event_trb: &CommandCompletion) { - lock().process_trb(event_trb) + // Just pop a TRB, not to process it within the controller to prevent a + // deadlock. + let trb = try_lock() + .expect("Failed to lock command ring controller") + .pop_corresponding_trb(event_trb); + + match trb { + command::Allowed::Noop(_) => {} + command::Allowed::EnableSlot(_) => { + ports::init_structures(event_trb.slot_id()); + } + command::Allowed::AddressDevice(_) => { + ports::init_structures(event_trb.slot_id()); + } + _ => panic!("Unexpected command TRB: {:?}", trb), + } } pub fn send_nop() { - lock().send_nop() + try_lock() + .expect("Failed to lock command ring controller") + .send_nop() } pub fn send_enable_slot() { - lock().send_enable_slot() + try_lock() + .expect("Failed to lock command ring controller") + .send_enable_slot() } pub fn send_address_device(input_cx_addr: u64, slot: u8) { - lock().send_address_device(input_cx_addr, slot) + try_lock() + .expect("Failed to lock command ring controller") + .send_address_device(input_cx_addr, slot) } -fn lock() -> impl DerefMut { +fn try_lock() -> Option> { COMMAND_RING_CONTROLLER .try_get() .expect("Command ring controller not initialized") .try_lock() - .expect("Command ring controller is already locked") } struct CommandRingController { @@ -70,7 +95,7 @@ impl CommandRingController { assert!(self.sent_trbs.is_empty(), "Some TRBs are not processed"); } - fn process_trb(&mut self, event_trb: &CommandCompletion) { + fn pop_corresponding_trb(&mut self, event_trb: &CommandCompletion) -> command::Allowed { let command_trb_idx = self .sent_trbs .iter() @@ -82,14 +107,11 @@ impl CommandRingController { assert_eq!( event_trb.completion_code(), Ok(CompletionCode::Success), - "Event TRB has an error code: {:?}", - event_trb.completion_code() + "Event TRB in response to a command TRB is not successful: {:?}", + command_trb ); - match command_trb { - command::Allowed::Noop(_) => {} - _ => panic!("Unexpected command TRB: {:?}", command_trb), - } + command_trb } fn send_nop(&mut self) { diff --git a/test/src/main.rs b/test/src/main.rs index 9f6b74b7..33426f58 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -37,6 +37,9 @@ fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> Ok(xhci::ring::trb::event::Allowed::CommandCompletion(x)) => { command_ring::process_trb(&x); } + Ok(xhci::ring::trb::event::Allowed::PortStatusChange(x)) => { + ports::process_trb(&x); + } Ok(x) => panic!("Unhandled TRB: {:?}", x), Err(x) => panic!("Unknown TRB: {:?}", x), } diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index 602a23f9..ffe118c4 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -3,18 +3,53 @@ mod context; use self::context::Context; use crate::dcbaa; use crate::{command_ring, registers, transfer_ring::TransferRingController}; +use alloc::vec::Vec; +use core::ops::DerefMut; +use spinning_top::Spinlock; +use xhci::ring::trb::event::PortStatusChange; use xhci::{context::EndpointType, registers::PortRegisterSet}; +static ENABLING_SLOTS: Spinlock> = Spinlock::new(Vec::new()); + pub fn init_all_ports() { let num_ports = num_ports(); for port in 0..num_ports { if connected(port) { - init_port(port); + reset_port(port); + command_ring::send_enable_slot(); + + lock_enabling_slots().push(port); } } } +pub fn process_trb(trb: &PortStatusChange) { + PortRegisterHandler::new(trb.port_id()).update(|r| { + if r.portsc.current_connect_status() { + todo!() + } + }); +} + +pub fn init_structures(slot: u8) { + let port = lock_enabling_slots().pop().expect("No enabling slots"); + + init_structures_for_port(port, slot); +} + +pub fn init_structures_for_port(port: u8, slot: u8) { + let mut cx = Context::new(); + + StructureInitializer::new(port, slot, cx).create(); +} + +fn lock_enabling_slots() -> impl DerefMut> { + ENABLING_SLOTS + .try_lock() + .expect("Enabling slots is already locked") +} + fn connected(port: u8) -> bool { registers::handle(|r| { r.port_register_set @@ -24,10 +59,8 @@ fn connected(port: u8) -> bool { }) } -fn init_port(port: u8) { +fn reset_port(port: u8) { Resetter::new(port).reset(); - - command_ring::send_enable_slot(); } fn num_ports() -> u8 { @@ -146,7 +179,9 @@ impl<'a> InputContextInitializer<'a> { let s = self.cx.input.device_mut().slot_mut(); s.set_context_entries(1); - s.set_root_hub_port_number(self.port); + + // Port ID starts from 1. + s.set_root_hub_port_number(self.port + 1); } } From 25498274b5f40b59039b58677b82f54e02ce7bc7 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 11:53:56 +0900 Subject: [PATCH 085/115] Doing --- test/src/command_ring.rs | 2 +- test/src/ports/mod.rs | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs index 16398811..1361bc9f 100644 --- a/test/src/command_ring.rs +++ b/test/src/command_ring.rs @@ -40,7 +40,7 @@ pub fn process_trb(event_trb: &CommandCompletion) { ports::init_structures(event_trb.slot_id()); } command::Allowed::AddressDevice(_) => { - ports::init_structures(event_trb.slot_id()); + ports::set_max_packet_size(event_trb.slot_id()); } _ => panic!("Unexpected command TRB: {:?}", trb), } diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs index ffe118c4..bbcb2aaa 100644 --- a/test/src/ports/mod.rs +++ b/test/src/ports/mod.rs @@ -10,6 +10,8 @@ use xhci::ring::trb::event::PortStatusChange; use xhci::{context::EndpointType, registers::PortRegisterSet}; static ENABLING_SLOTS: Spinlock> = Spinlock::new(Vec::new()); +static PORTS_AND_SLOTS: Spinlock> = Spinlock::new(Vec::new()); +static CONTEXTS: Spinlock> = Spinlock::new(Vec::new()); pub fn init_all_ports() { let num_ports = num_ports(); @@ -35,6 +37,11 @@ pub fn process_trb(trb: &PortStatusChange) { pub fn init_structures(slot: u8) { let port = lock_enabling_slots().pop().expect("No enabling slots"); + PORTS_AND_SLOTS + .try_lock() + .expect("Ports and slots is already locked") + .push((port, slot)); + init_structures_for_port(port, slot); } @@ -44,6 +51,16 @@ pub fn init_structures_for_port(port: u8, slot: u8) { StructureInitializer::new(port, slot, cx).create(); } +pub fn set_max_packet_size(slot: u8) { + let port = PORTS_AND_SLOTS + .try_lock() + .expect("Ports and slots is already locked") + .iter() + .find(|(_, s)| *s == slot) + .expect("No port for the slot") + .0; +} + fn lock_enabling_slots() -> impl DerefMut> { ENABLING_SLOTS .try_lock() @@ -124,11 +141,16 @@ impl StructureInitializer { } } - fn create(&mut self) { + fn create(mut self) { self.init_input_context(); self.init_ep0_context(); self.register_with_dcbaa(); self.issue_address_device_command(); + + CONTEXTS + .try_lock() + .expect("Contexts is already locked") + .push(self.cx); } fn init_input_context(&mut self) { From f3c05694ddc197bac6dc135650810e6ecb3346bb Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 14:53:15 +0900 Subject: [PATCH 086/115] This code is taken from my ramen OS --- test/src/ports/context.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/src/ports/context.rs b/test/src/ports/context.rs index cabd5455..a37a2e3d 100644 --- a/test/src/ports/context.rs +++ b/test/src/ports/context.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - use crate::registers; use { From c3a468c0adaafe776410ea3079a88caf2c58b53e Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 15:25:07 +0900 Subject: [PATCH 087/115] Do not print --- test/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index 54cd1715..68efb1e3 100644 --- a/test/Makefile +++ b/test/Makefile @@ -32,7 +32,6 @@ $(IMG): $(EFI) build mcopy -i $@ $(EFI) ::/efi/boot/bootx64.efi $(EFI): $(shell find src/) Cargo.toml - echo $^ cargo build build: From 1c4d776604e1d2efeab84e39fa97635d9917d9b4 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 16:53:40 +0900 Subject: [PATCH 088/115] Copy code from my Ramen OS because I'm very tired. Code from https://github.com/toku-sa-n/ramen/tree/00193f21cdb72f37e5b4059a1e47c9be88992f5c. This revision does not include contributions from the other contributors except bots, and thus it does not violate GPL as I'm the author of it. --- test/Cargo.toml | 24 +- test/src/command_ring.rs | 240 --------------- test/src/dcbaa.rs | 67 ----- test/src/event.rs | 203 ------------- test/src/exchanger/command.rs | 131 ++++++++ test/src/exchanger/mod.rs | 5 + test/src/exchanger/receiver.rs | 144 +++++++++ test/src/exchanger/transfer.rs | 252 ++++++++++++++++ test/src/main.rs | 111 +++++-- test/src/multitask/executor.rs | 79 +++++ test/src/multitask/mod.rs | 16 + test/src/multitask/task.rs | 146 +++++++++ test/src/pci.rs | 149 ---------- test/src/pci/config/bar.rs | 81 +++++ test/src/pci/config/common.rs | 91 ++++++ test/src/pci/config/mod.rs | 174 +++++++++++ test/src/pci/config/type_spec/mod.rs | 29 ++ test/src/pci/config/type_spec/non_bridge.rs | 36 +++ test/src/pci/mod.rs | 42 +++ test/src/port/class_driver/keyboard.rs | 89 ++++++ .../src/port/class_driver/mass_storage/mod.rs | 195 ++++++++++++ .../mass_storage/scsi/command_data_block.rs | 109 +++++++ .../class_driver/mass_storage/scsi/mod.rs | 76 +++++ .../mass_storage/scsi/response.rs | 46 +++ test/src/port/class_driver/mod.rs | 5 + test/src/port/class_driver/mouse.rs | 91 ++++++ test/src/port/endpoint.rs | 71 +++++ test/src/port/init/descriptor_fetcher.rs | 101 +++++++ test/src/port/init/endpoints_initializer.rs | 281 ++++++++++++++++++ test/src/port/init/fully_operational.rs | 84 ++++++ test/src/port/init/max_packet_size_setter.rs | 74 +++++ test/src/port/init/mod.rs | 20 ++ test/src/port/init/resetter.rs | 58 ++++ .../port/init/slot_structures_initializer.rs | 152 ++++++++++ test/src/port/mod.rs | 114 +++++++ test/src/port/spawner.rs | 50 ++++ test/src/ports/context.rs | 75 ----- test/src/ports/endpoint.rs | 0 test/src/ports/mod.rs | 277 ----------------- test/src/registers.rs | 42 --- test/src/scratchpat.rs | 14 - test/src/structures/context.rs | 78 +++++ test/src/structures/dcbaa.rs | 70 +++++ test/src/structures/descriptor.rs | 162 ++++++++++ test/src/structures/extended_capabilities.rs | 39 +++ test/src/structures/mod.rs | 9 + test/src/structures/registers.rs | 34 +++ test/src/structures/ring/command/mod.rs | 145 +++++++++ test/src/structures/ring/event/mod.rs | 259 ++++++++++++++++ .../structures/ring/event/segment_table.rs | 70 +++++ test/src/structures/ring/mod.rs | 22 ++ test/src/structures/ring/transfer/mod.rs | 101 +++++++ test/src/structures/scratchpad.rs | 83 ++++++ test/src/transfer_ring.rs | 26 -- test/src/transition_helper.rs | 61 ++++ test/src/xhc.rs | 197 +++++------- test/x86_64-unknown-ramen.json | 22 ++ 57 files changed, 4177 insertions(+), 1245 deletions(-) delete mode 100644 test/src/command_ring.rs delete mode 100644 test/src/dcbaa.rs delete mode 100644 test/src/event.rs create mode 100644 test/src/exchanger/command.rs create mode 100644 test/src/exchanger/mod.rs create mode 100644 test/src/exchanger/receiver.rs create mode 100644 test/src/exchanger/transfer.rs create mode 100644 test/src/multitask/executor.rs create mode 100644 test/src/multitask/mod.rs create mode 100644 test/src/multitask/task.rs delete mode 100644 test/src/pci.rs create mode 100644 test/src/pci/config/bar.rs create mode 100644 test/src/pci/config/common.rs create mode 100644 test/src/pci/config/mod.rs create mode 100644 test/src/pci/config/type_spec/mod.rs create mode 100644 test/src/pci/config/type_spec/non_bridge.rs create mode 100644 test/src/pci/mod.rs create mode 100644 test/src/port/class_driver/keyboard.rs create mode 100644 test/src/port/class_driver/mass_storage/mod.rs create mode 100644 test/src/port/class_driver/mass_storage/scsi/command_data_block.rs create mode 100644 test/src/port/class_driver/mass_storage/scsi/mod.rs create mode 100644 test/src/port/class_driver/mass_storage/scsi/response.rs create mode 100644 test/src/port/class_driver/mod.rs create mode 100644 test/src/port/class_driver/mouse.rs create mode 100644 test/src/port/endpoint.rs create mode 100644 test/src/port/init/descriptor_fetcher.rs create mode 100644 test/src/port/init/endpoints_initializer.rs create mode 100644 test/src/port/init/fully_operational.rs create mode 100644 test/src/port/init/max_packet_size_setter.rs create mode 100644 test/src/port/init/mod.rs create mode 100644 test/src/port/init/resetter.rs create mode 100644 test/src/port/init/slot_structures_initializer.rs create mode 100644 test/src/port/mod.rs create mode 100644 test/src/port/spawner.rs delete mode 100644 test/src/ports/context.rs delete mode 100644 test/src/ports/endpoint.rs delete mode 100644 test/src/ports/mod.rs delete mode 100644 test/src/registers.rs delete mode 100644 test/src/scratchpat.rs create mode 100644 test/src/structures/context.rs create mode 100644 test/src/structures/dcbaa.rs create mode 100644 test/src/structures/descriptor.rs create mode 100644 test/src/structures/extended_capabilities.rs create mode 100644 test/src/structures/mod.rs create mode 100644 test/src/structures/registers.rs create mode 100644 test/src/structures/ring/command/mod.rs create mode 100644 test/src/structures/ring/event/mod.rs create mode 100644 test/src/structures/ring/event/segment_table.rs create mode 100644 test/src/structures/ring/mod.rs create mode 100644 test/src/structures/ring/transfer/mod.rs create mode 100644 test/src/structures/scratchpad.rs delete mode 100644 test/src/transfer_ring.rs create mode 100644 test/src/transition_helper.rs create mode 100644 test/x86_64-unknown-ramen.json diff --git a/test/Cargo.toml b/test/Cargo.toml index 3c6a1cb1..ef2c91d9 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -4,12 +4,28 @@ version = "0.1.0" edition = "2021" [dependencies] -bit_field = "0.10.2" -conquer-once = { version = "0.4.0", default-features = false } +accessor = "0.3.0" +bit_field = "0.10.1" +byteorder = { version = "1.4.3", default-features = false } +conquer-once = { version = "0.3.2", default-features = false } +crossbeam-queue = { version = "0.3.1", features = [ + "alloc", +], default-features = false } +derive_builder = { version = "0.10.2", default-features = false } +futures-intrusive = { version = "0.4.0", features = [ + "alloc", +], default-features = false } +futures-util = { version = "0.3.15", features = [ + "alloc", +], default-features = false } linked_list_allocator = "0.10.5" +log = "0.4.14" +num-derive = "0.3.3" +num-traits = { version = "0.2.14", default-features = false } +os_units = "0.4.0" qemu-exit = "3.0.2" -qemu_print = { version = "0.1.0", features = ["stable"], default-features = false } -spinning_top = "0.3.0" +qemu_print = { version = "0.1.0", default-features = false, features = ["stable"] } +spinning_top = { version = "0.2.4", features = ["nightly"] } uefi = "0.26.0" x86_64 = { version = "0.14.11", default-features = false } xhci = { version = "0.9.2", path = "../lib" } diff --git a/test/src/command_ring.rs b/test/src/command_ring.rs deleted file mode 100644 index 1361bc9f..00000000 --- a/test/src/command_ring.rs +++ /dev/null @@ -1,240 +0,0 @@ -use crate::ports; -use crate::registers; -use alloc::{boxed::Box, vec::Vec}; -use conquer_once::spin::OnceCell; -use core::ops::DerefMut; -use spinning_top::Spinlock; -use xhci::ring::trb::{ - self, command, - event::{CommandCompletion, CompletionCode}, -}; - -const NUM_OF_TRBS_IN_RING: usize = 16; - -static COMMAND_RING_CONTROLLER: OnceCell> = OnceCell::uninit(); - -pub fn init() { - COMMAND_RING_CONTROLLER.init_once(|| Spinlock::new(CommandRingController::new())); - - try_lock() - .expect("Failed to lock command ring controller") - .init(); -} - -pub fn assert_all_trbs_are_processed() { - try_lock() - .expect("Failed to lock command ring controller") - .assert_all_trbs_are_processed() -} - -pub fn process_trb(event_trb: &CommandCompletion) { - // Just pop a TRB, not to process it within the controller to prevent a - // deadlock. - let trb = try_lock() - .expect("Failed to lock command ring controller") - .pop_corresponding_trb(event_trb); - - match trb { - command::Allowed::Noop(_) => {} - command::Allowed::EnableSlot(_) => { - ports::init_structures(event_trb.slot_id()); - } - command::Allowed::AddressDevice(_) => { - ports::set_max_packet_size(event_trb.slot_id()); - } - _ => panic!("Unexpected command TRB: {:?}", trb), - } -} - -pub fn send_nop() { - try_lock() - .expect("Failed to lock command ring controller") - .send_nop() -} - -pub fn send_enable_slot() { - try_lock() - .expect("Failed to lock command ring controller") - .send_enable_slot() -} - -pub fn send_address_device(input_cx_addr: u64, slot: u8) { - try_lock() - .expect("Failed to lock command ring controller") - .send_address_device(input_cx_addr, slot) -} - -fn try_lock() -> Option> { - COMMAND_RING_CONTROLLER - .try_get() - .expect("Command ring controller not initialized") - .try_lock() -} - -struct CommandRingController { - ring: Box, - - sent_trbs: Vec<(u64, command::Allowed)>, - - enqueue_ptr: usize, - cycle_bit: bool, -} -impl CommandRingController { - fn new() -> Self { - Self { - ring: Box::new(CommandRing::new()), - - sent_trbs: Vec::new(), - - enqueue_ptr: 0, - cycle_bit: true, - } - } - - fn assert_all_trbs_are_processed(&self) { - assert!(self.sent_trbs.is_empty(), "Some TRBs are not processed"); - } - - fn pop_corresponding_trb(&mut self, event_trb: &CommandCompletion) -> command::Allowed { - let command_trb_idx = self - .sent_trbs - .iter() - .position(|(addr, _)| *addr == event_trb.command_trb_pointer()) - .expect("Command TRB not found"); - - let (_, command_trb) = self.sent_trbs.remove(command_trb_idx); - - assert_eq!( - event_trb.completion_code(), - Ok(CompletionCode::Success), - "Event TRB in response to a command TRB is not successful: {:?}", - command_trb - ); - - command_trb - } - - fn send_nop(&mut self) { - let trb = command::Noop::new(); - let trb = command::Allowed::Noop(trb); - - self.enqueue(trb) - } - - fn send_enable_slot(&mut self) { - let trb = command::EnableSlot::new(); - let trb = command::Allowed::EnableSlot(trb); - - self.enqueue(trb) - } - - fn send_address_device(&mut self, input_cx_addr: u64, slot: u8) { - let trb = *command::AddressDevice::new() - .set_input_context_pointer(input_cx_addr) - .set_slot_id(slot); - let trb = command::Allowed::AddressDevice(trb); - - self.enqueue(trb) - } - - fn enqueue(&mut self, trb: command::Allowed) { - Enqueuer::new(self).enqueue(trb) - } - - fn init(&mut self) { - registers::handle(|r| { - r.operational.crcr.update_volatile(|crcr| { - crcr.set_command_ring_pointer(self.ring.as_ref() as *const _ as u64); - crcr.set_ring_cycle_state(); - }); - }) - } -} - -struct Enqueuer<'a> { - controller: &'a mut CommandRingController, -} -impl<'a> Enqueuer<'a> { - fn new(controller: &'a mut CommandRingController) -> Self { - Self { controller } - } - - fn enqueue(&mut self, mut trb: command::Allowed) { - self.modify_cycle_bit(&mut trb); - self.write_trb(trb); - - let a = self.written_trb_address(); - - self.store_trb(a, trb); - - self.increment_enqueue_ptr(); - self.notify_command_is_sent(); - } - - fn enqueue_link(&mut self) { - let link_trb = *trb::Link::new().set_ring_segment_pointer(self.ring_head_address()); - let mut link_trb = command::Allowed::Link(link_trb); - - self.modify_cycle_bit(&mut link_trb); - self.write_trb(link_trb); - self.move_enqueue_ptr_to_head(); - } - - fn modify_cycle_bit(&mut self, trb: &mut command::Allowed) { - if self.controller.cycle_bit { - trb.set_cycle_bit(); - } else { - trb.clear_cycle_bit(); - } - } - - fn write_trb(&mut self, trb: command::Allowed) { - self.controller.ring.0[self.controller.enqueue_ptr] = trb.into_raw(); - } - - fn written_trb_address(&self) -> u64 { - &self.controller.ring.0[self.controller.enqueue_ptr] as *const _ as u64 - } - - fn increment_enqueue_ptr(&mut self) { - self.controller.enqueue_ptr += 1; - - if !self.can_enqueue_trbs() { - self.enqueue_link(); - } - } - - fn notify_command_is_sent(&mut self) { - registers::handle(|r| { - r.doorbell.update_volatile_at(0, |r| { - r.set_doorbell_target(0); - }); - }) - } - - fn store_trb(&mut self, addr: u64, trb: command::Allowed) { - self.controller.sent_trbs.push((addr, trb)); - } - - fn can_enqueue_trbs(&self) -> bool { - // -1 for the space for a link TRB. - self.controller.enqueue_ptr < NUM_OF_TRBS_IN_RING - 1 - } - - fn move_enqueue_ptr_to_head(&mut self) { - self.controller.enqueue_ptr = 0; - self.controller.cycle_bit = !self.controller.cycle_bit; - } - - fn ring_head_address(&self) -> u64 { - self.controller.ring.as_ref() as *const _ as u64 - } -} - -#[repr(C, align(64))] -struct CommandRing([[u32; 4]; NUM_OF_TRBS_IN_RING]); -impl CommandRing { - fn new() -> Self { - Self([[0; 4]; NUM_OF_TRBS_IN_RING]) - } -} diff --git a/test/src/dcbaa.rs b/test/src/dcbaa.rs deleted file mode 100644 index f3c31562..00000000 --- a/test/src/dcbaa.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::registers; -use alloc::vec; -use alloc::vec::Vec; -use conquer_once::spin::OnceCell; -use spinning_top::Spinlock; - -static DCBAA: OnceCell> = OnceCell::uninit(); - -pub fn init() { - DCBAA.init_once(|| Spinlock::new(DeviceContextBaseAddressArray::new())); - - lock().init(); -} - -pub fn register_address(port: u8, addr: u64) { - lock().register_address(port, addr); -} - -fn lock() -> impl core::ops::DerefMut { - DCBAA - .try_get() - .expect("Device context base address array not initialized") - .try_lock() - .expect("Device context base address array is already locked") -} - -struct DeviceContextBaseAddressArray(Vec); -impl DeviceContextBaseAddressArray { - fn new() -> Self { - Self(vec![RawDCBAA::new(); number_of_slots()]) - } - - fn register_address(&mut self, port: u8, addr: u64) { - self.0[port as usize].0 = addr; - } - - fn init(&mut self) { - self.register_address_with_register(); - } - - fn register_address_with_register(&self) { - registers::handle(|r| { - r.operational - .dcbaap - .update_volatile(|dcbaap| dcbaap.set(self.0.as_ptr() as u64)); - }) - } -} - -#[repr(C, align(64))] -#[derive(Clone, Copy)] -struct RawDCBAA(u64); -impl RawDCBAA { - fn new() -> Self { - Self(0) - } -} - -fn number_of_slots() -> usize { - registers::handle(|r| { - r.capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() as usize - + 1_usize - }) -} diff --git a/test/src/event.rs b/test/src/event.rs deleted file mode 100644 index 1aa81ea5..00000000 --- a/test/src/event.rs +++ /dev/null @@ -1,203 +0,0 @@ -use crate::registers; -use alloc::{vec, vec::Vec}; -use bit_field::BitField; -use conquer_once::spin::OnceCell; -use core::ops::DerefMut; -use spinning_top::Spinlock; -use xhci::ring::trb::event; -use xhci::ring::trb::{self}; - -const NUM_OF_TRBS_IN_RING: usize = 16; - -static EVENT_HANDLER: OnceCell> = OnceCell::uninit(); - -pub fn init() { - EVENT_HANDLER.init_once(|| Spinlock::new(EventHandler::new())); - - lock().init(); -} - -pub fn dequeue() -> Option> { - lock().dequeue() -} - -fn lock() -> impl DerefMut { - EVENT_HANDLER - .try_get() - .expect("Event handler not initialized") - .try_lock() - .expect("Event handler is already locked") -} - -struct EventHandler { - segment_table: Vec, - rings: Vec, - - dequeue_ptr_segment: u64, - dequeue_ptr_ring: u64, - - cycle_bit: bool, -} -impl EventHandler { - fn new() -> Self { - let number_of_rings = number_of_rings(); - - Self { - segment_table: vec![EventRingSegmentTableEntry::null(); number_of_rings.into()], - rings: vec![EventRing::new(); number_of_rings.into()], - - dequeue_ptr_segment: 0, - dequeue_ptr_ring: 0, - - cycle_bit: true, - } - } - - fn init(&mut self) { - EventHandlerInitializer::new(self).init(); - } - - pub fn dequeue(&mut self) -> Option> { - if self.ring_is_empty() { - return None; - } - - let t = self.rings[self.dequeue_ptr_segment as usize].0[self.dequeue_ptr_ring as usize]; - let t = event::Allowed::try_from(t); - - self.increment_ptr(); - - Some(t) - } - - fn increment_ptr(&mut self) { - self.dequeue_ptr_ring += 1; - - if self.dequeue_ptr_ring >= NUM_OF_TRBS_IN_RING as u64 { - self.dequeue_ptr_ring = 0; - self.dequeue_ptr_segment += 1; - - if self.dequeue_ptr_segment >= self.segment_table.len() as u64 { - self.dequeue_ptr_segment = 0; - self.cycle_bit = !self.cycle_bit; - } - } - } - - fn ring_is_empty(&self) -> bool { - self.cycle_bit_of_next_trb() != self.cycle_bit - } - - fn cycle_bit_of_next_trb(&self) -> bool { - let t = self.rings[self.dequeue_ptr_segment as usize].0[self.dequeue_ptr_ring as usize]; - - t[3].get_bit(0) - } - - fn next_trb_addr(&self) -> u64 { - &self.rings[self.dequeue_ptr_segment as usize] as *const _ as u64 - + self.dequeue_ptr_ring as u64 * trb::BYTES as u64 - } -} - -struct EventHandlerInitializer<'a> { - handler: &'a mut EventHandler, -} -impl<'a> EventHandlerInitializer<'a> { - fn new(handler: &'a mut EventHandler) -> Self { - Self { handler } - } - - fn init(&mut self) { - self.register_dequeue_pointer(); - self.write_rings_addresses_in_table(); - self.disable_interrupts(); - self.register_table_size(); - self.enable_event_ring(); - } - - fn register_dequeue_pointer(&mut self) { - registers::handle(|r| { - r.interrupter_register_set - .interrupter_mut(0) - .erdp - .update_volatile(|erdp| { - erdp.set_event_ring_dequeue_pointer(self.handler.next_trb_addr()) - }) - }) - } - - fn write_rings_addresses_in_table(&mut self) { - let segment_table = &mut self.handler.segment_table; - - for (i, ring) in self.handler.rings.iter().enumerate() { - segment_table[i].base_addr = ring as *const _ as u64; - segment_table[i].segment_size = NUM_OF_TRBS_IN_RING as _; - } - } - - // We use polling for simplicity. - fn disable_interrupts(&mut self) { - registers::handle(|r| { - r.interrupter_register_set - .interrupter_mut(0) - .iman - .update_volatile(|iman| { - iman.clear_interrupt_enable(); - }) - }) - } - - fn register_table_size(&mut self) { - registers::handle(|r| { - r.interrupter_register_set - .interrupter_mut(0) - .erstsz - .update_volatile(|erstsz| { - erstsz.set(self.handler.segment_table.len() as u16); - }) - }) - } - - fn enable_event_ring(&mut self) { - registers::handle(|r| { - r.interrupter_register_set - .interrupter_mut(0) - .erstba - .update_volatile(|erstba| erstba.set(self.handler.segment_table.as_ptr() as u64)) - }) - } -} - -#[repr(C, align(64))] -#[derive(Clone, Copy, Debug)] -struct EventRingSegmentTableEntry { - base_addr: u64, - segment_size: u64, -} -impl EventRingSegmentTableEntry { - fn null() -> Self { - Self { - base_addr: 0, - segment_size: 0, - } - } -} - -#[repr(C, align(64))] -#[derive(Clone, Copy, Debug)] -struct EventRing([[u32; 4]; NUM_OF_TRBS_IN_RING]); -impl EventRing { - fn new() -> Self { - Self([[0; 4]; NUM_OF_TRBS_IN_RING]) - } -} - -fn number_of_rings() -> u16 { - registers::handle(|r| { - r.capability - .hcsparams2 - .read_volatile() - .event_ring_segment_table_max() - }) -} diff --git a/test/src/exchanger/command.rs b/test/src/exchanger/command.rs new file mode 100644 index 00000000..981bc909 --- /dev/null +++ b/test/src/exchanger/command.rs @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::{ + super::structures::ring::command, + receiver::{self, ReceiveFuture}, +}; +use crate::{Futurelock, FuturelockGuard}; +use alloc::sync::Arc; +use command_trb::{AddressDevice, ConfigureEndpoint, EnableSlot, EvaluateContext}; +use conquer_once::spin::OnceCell; +use event::CompletionCode; +use futures_util::task::AtomicWaker; +use spinning_top::Spinlock; +use x86_64::PhysAddr; +use xhci::ring::trb::{command as command_trb, event}; + +static SENDER: OnceCell> = OnceCell::uninit(); + +pub(crate) fn init(r: Arc>) { + SENDER + .try_init_once(|| Futurelock::new(Sender::new(r), true)) + .expect("`Sender` is initialized more than once.") +} + +pub(crate) async fn enable_device_slot() -> u8 { + lock().await.enable_device_slot().await +} + +pub(crate) async fn address_device(input_cx: PhysAddr, slot: u8) { + lock().await.address_device(input_cx, slot).await; +} + +pub(crate) async fn configure_endpoint(cx: PhysAddr, slot: u8) { + lock().await.configure_endpoint(cx, slot).await; +} + +pub(crate) async fn evaluate_context(cx: PhysAddr, slot: u8) { + lock().await.evaluate_context(cx, slot).await; +} + +async fn lock() -> FuturelockGuard<'static, Sender> { + let s = SENDER.try_get().expect("`SENDER` is not initialized."); + s.lock().await +} + +struct Sender { + channel: Channel, +} +impl Sender { + fn new(ring: Arc>) -> Self { + Self { + channel: Channel::new(ring), + } + } + + async fn enable_device_slot(&mut self) -> u8 { + let t = EnableSlot::default(); + let completion = self.send_and_receive(t.into()).await; + panic_on_error("Enable Device Slot", completion); + if let event::Allowed::CommandCompletion(c) = completion { + c.slot_id() + } else { + unreachable!() + } + } + + async fn address_device(&mut self, input_context_addr: PhysAddr, slot_id: u8) { + let t = *AddressDevice::default() + .set_input_context_pointer(input_context_addr.as_u64()) + .set_slot_id(slot_id); + let c = self.send_and_receive(t.into()).await; + panic_on_error("Address Device", c); + } + + async fn configure_endpoint(&mut self, context_addr: PhysAddr, slot_id: u8) { + let t = *ConfigureEndpoint::default() + .set_input_context_pointer(context_addr.as_u64()) + .set_slot_id(slot_id); + let c = self.send_and_receive(t.into()).await; + panic_on_error("Configure Endpoint", c); + } + + async fn evaluate_context(&mut self, cx: PhysAddr, slot: u8) { + let t = *EvaluateContext::default() + .set_input_context_pointer(cx.as_u64()) + .set_slot_id(slot); + let c = self.send_and_receive(t.into()).await; + panic_on_error("Evaluate Context", c); + } + + async fn send_and_receive(&mut self, t: command_trb::Allowed) -> event::Allowed { + self.channel.send_and_receive(t).await + } +} + +struct Channel { + ring: Arc>, + waker: Arc>, +} +impl Channel { + fn new(ring: Arc>) -> Self { + Self { + ring, + waker: Arc::new(Spinlock::new(AtomicWaker::new())), + } + } + + async fn send_and_receive(&mut self, t: command_trb::Allowed) -> event::Allowed { + let a = self.ring.lock().enqueue(t); + self.register_with_receiver(a); + self.get_trb(a).await + } + + fn register_with_receiver(&mut self, trb_a: PhysAddr) { + receiver::add_entry(trb_a, self.waker.clone()).expect("Sender is already registered."); + } + + async fn get_trb(&mut self, trb_a: PhysAddr) -> event::Allowed { + ReceiveFuture::new(trb_a, self.waker.clone()).await + } +} + +fn panic_on_error(n: &str, c: event::Allowed) { + if let event::Allowed::CommandCompletion(c) = c { + if c.completion_code() != Ok(CompletionCode::Success) { + panic!("{} command failed: {:?}", n, c.completion_code()); + } + } else { + unreachable!("The Command Completion TRB is the only TRB to receive in response to the Command TRBs.") + } +} diff --git a/test/src/exchanger/mod.rs b/test/src/exchanger/mod.rs new file mode 100644 index 00000000..0df9546c --- /dev/null +++ b/test/src/exchanger/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub(crate) mod command; +pub(crate) mod receiver; +pub(crate) mod transfer; diff --git a/test/src/exchanger/receiver.rs b/test/src/exchanger/receiver.rs new file mode 100644 index 00000000..ecfff20e --- /dev/null +++ b/test/src/exchanger/receiver.rs @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use alloc::{collections::BTreeMap, sync::Arc}; +use conquer_once::spin::Lazy; +use core::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; +use futures_util::task::AtomicWaker; +use spinning_top::{Spinlock, SpinlockGuard}; +use x86_64::PhysAddr; +use xhci::ring::trb::event; + +static RECEIVER: Lazy> = Lazy::new(|| Spinlock::new(Receiver::new())); + +pub(crate) fn add_entry(trb_a: PhysAddr, waker: Arc>) -> Result<(), Error> { + lock().add_entry(trb_a, waker) +} + +pub(crate) fn receive(t: event::Allowed) { + lock().receive(t) +} + +fn lock() -> SpinlockGuard<'static, Receiver> { + RECEIVER + .try_lock() + .expect("Failed to acquire the lock of `RECEIVER`.") +} + +struct Receiver { + trbs: BTreeMap>, + wakers: BTreeMap>>, +} +impl Receiver { + fn new() -> Self { + Self { + trbs: BTreeMap::new(), + wakers: BTreeMap::new(), + } + } + + fn add_entry( + &mut self, + addr_to_trb: PhysAddr, + waker: Arc>, + ) -> Result<(), Error> { + if self.trbs.insert(addr_to_trb, None).is_some() { + return Err(Error::AddrAlreadyRegistered); + } + + if self.wakers.insert(addr_to_trb, waker).is_some() { + return Err(Error::AddrAlreadyRegistered); + } + Ok(()) + } + + fn receive(&mut self, trb: event::Allowed) { + if let Err(e) = self.insert_trb_and_wake_runner(trb) { + panic!("Failed to receive a command completion trb: {:?}", e); + } + } + + fn insert_trb_and_wake_runner(&mut self, trb: event::Allowed) -> Result<(), Error> { + let addr_to_trb = Self::trb_addr(trb); + self.insert_trb(trb)?; + self.wake_runner(addr_to_trb)?; + Ok(()) + } + + fn insert_trb(&mut self, trb: event::Allowed) -> Result<(), Error> { + let addr_to_trb = Self::trb_addr(trb); + *self + .trbs + .get_mut(&addr_to_trb) + .ok_or(Error::NoSuchAddress)? = Some(trb); + Ok(()) + } + + fn wake_runner(&mut self, addr_to_trb: PhysAddr) -> Result<(), Error> { + self.wakers + .remove(&addr_to_trb) + .ok_or(Error::NoSuchAddress)? + .lock() + .wake(); + Ok(()) + } + + fn trb_arrives(&self, addr_to_trb: PhysAddr) -> bool { + match self.trbs.get(&addr_to_trb) { + Some(trb) => trb.is_some(), + None => panic!("No such TRB with the address {:?}", addr_to_trb), + } + } + + fn remove_entry(&mut self, addr_to_trb: PhysAddr) -> Option { + match self.trbs.remove(&addr_to_trb) { + Some(trb) => trb, + None => panic!("No such receiver with TRB address: {:?}", addr_to_trb), + } + } + + fn trb_addr(t: event::Allowed) -> PhysAddr { + PhysAddr::new(match t { + event::Allowed::TransferEvent(e) => e.trb_pointer(), + event::Allowed::CommandCompletion(c) => c.command_trb_pointer(), + _ => todo!(), + }) + } +} + +#[derive(Debug)] +pub(crate) enum Error { + AddrAlreadyRegistered, + NoSuchAddress, +} + +pub(crate) struct ReceiveFuture { + addr_to_trb: PhysAddr, + waker: Arc>, +} +impl ReceiveFuture { + pub(crate) fn new(addr_to_trb: PhysAddr, waker: Arc>) -> Self { + Self { addr_to_trb, waker } + } +} +impl Future for ReceiveFuture { + type Output = event::Allowed; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let waker = self.waker.clone(); + let addr = self.addr_to_trb; + let mut r = lock(); + + waker.lock().register(cx.waker()); + if r.trb_arrives(addr) { + waker.lock().take(); + let trb = r.remove_entry(addr).unwrap(); + Poll::Ready(trb) + } else { + Poll::Pending + } + } +} diff --git a/test/src/exchanger/transfer.rs b/test/src/exchanger/transfer.rs new file mode 100644 index 00000000..a70c1663 --- /dev/null +++ b/test/src/exchanger/transfer.rs @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::receiver::{self, ReceiveFuture}; +use crate::structures::{descriptor, registers, ring::transfer}; +use crate::transition_helper::BoxWrapper; +use alloc::{sync::Arc, vec::Vec}; +use core::convert::TryInto; +use futures_util::task::AtomicWaker; +use log::debug; +use spinning_top::Spinlock; +use x86_64::PhysAddr; +use xhci::ring::trb::{ + event, transfer as transfer_trb, + transfer::{Direction, Normal, TransferType}, +}; + +pub(crate) struct Sender { + channel: Channel, +} +impl Sender { + pub(crate) fn new(doorbell_writer: DoorbellWriter) -> Self { + Self { + channel: Channel::new(doorbell_writer), + } + } + + pub(crate) fn ring_addr(&self) -> PhysAddr { + self.channel.ring_addr() + } + + pub(crate) async fn get_max_packet_size_from_device_descriptor(&mut self) -> u16 { + let b = BoxWrapper::from(descriptor::Device::default()); + + let setup = *transfer_trb::SetupStage::default() + .set_transfer_type(TransferType::In) + .clear_interrupt_on_completion() + .set_request_type(0x80) + .set_request(6) + .set_value(0x0100) + .set_length(8); + + let data = *transfer_trb::DataStage::default() + .set_direction(Direction::In) + .set_trb_transfer_length(8) + .clear_interrupt_on_completion() + .set_data_buffer_pointer(b.phys_addr().as_u64()); + + let status = *transfer_trb::StatusStage::default().set_interrupt_on_completion(); + + self.issue_trbs(&[setup.into(), data.into(), status.into()]) + .await; + + b.max_packet_size() + } + + pub(crate) async fn set_configure(&mut self, config_val: u8) { + let setup = *transfer_trb::SetupStage::default() + .set_transfer_type(TransferType::No) + .clear_interrupt_on_completion() + .set_request_type(0) + .set_request(9) + .set_value(config_val.into()) + .set_length(0); + + let status = *transfer_trb::StatusStage::default().set_interrupt_on_completion(); + + self.issue_trbs(&[setup.into(), status.into()]).await; + } + + pub(crate) async fn set_idle(&mut self) { + let setup = *transfer_trb::SetupStage::default() + .set_transfer_type(TransferType::No) + .clear_interrupt_on_completion() + .set_request_type(0x21) + .set_request(0x0a) + .set_value(0) + .set_length(0); + + let status = *transfer_trb::StatusStage::default().set_interrupt_on_completion(); + + self.issue_trbs(&[setup.into(), status.into()]).await; + } + + pub(crate) async fn set_boot_protocol(&mut self) { + let setup = *transfer_trb::SetupStage::default() + .set_transfer_type(TransferType::No) + .clear_interrupt_on_completion() + .set_request_type(0b0010_0001) + .set_request(0x0b) + .set_value(0) + .set_length(0); + + let status = *transfer_trb::StatusStage::default().set_interrupt_on_completion(); + + self.issue_trbs(&[setup.into(), status.into()]).await; + } + + pub(crate) async fn get_configuration_descriptor(&mut self) -> BoxWrapper<[u8]> { + let b = BoxWrapper::new_slice(0, 4096); + + let (setup, data, status) = Self::trbs_for_getting_descriptors( + &b, + DescTyIdx::new(descriptor::Ty::Configuration, 0), + ); + + self.issue_trbs(&[setup, data, status]).await; + debug!("Got TRBs"); + b + } + + pub(crate) async fn issue_normal_trb(&mut self, b: &BoxWrapper) { + let t = *Normal::default() + .set_data_buffer_pointer(b.phys_addr().as_u64()) + .set_trb_transfer_length(b.bytes().as_usize().try_into().unwrap()) + .set_interrupt_on_completion(); + debug!("Normal TRB: {:X?}", t); + self.issue_trbs(&[t.into()]).await; + } + + fn trbs_for_getting_descriptors( + b: &BoxWrapper, + t: DescTyIdx, + ) -> ( + transfer_trb::Allowed, + transfer_trb::Allowed, + transfer_trb::Allowed, + ) { + let setup = *transfer_trb::SetupStage::default() + .set_request_type(0b1000_0000) + .set_request(Request::GetDescriptor as u8) + .set_value(t.bits()) + .set_length(b.bytes().as_usize().try_into().unwrap()) + .set_transfer_type(TransferType::In); + + let data = *transfer_trb::DataStage::default() + .set_data_buffer_pointer(b.phys_addr().as_u64()) + .set_trb_transfer_length(b.bytes().as_usize().try_into().unwrap()) + .set_direction(Direction::In); + + let status = *transfer_trb::StatusStage::default().set_interrupt_on_completion(); + + (setup.into(), data.into(), status.into()) + } + + async fn issue_trbs(&mut self, ts: &[transfer_trb::Allowed]) -> Vec> { + self.channel.send_and_receive(ts).await + } +} + +struct Channel { + ring: transfer::Ring, + doorbell_writer: DoorbellWriter, + waker: Arc>, +} +impl Channel { + fn new(doorbell_writer: DoorbellWriter) -> Self { + Self { + ring: transfer::Ring::new(), + doorbell_writer, + waker: Arc::new(Spinlock::new(AtomicWaker::new())), + } + } + + fn ring_addr(&self) -> PhysAddr { + self.ring.phys_addr() + } + + async fn send_and_receive( + &mut self, + trbs: &[transfer_trb::Allowed], + ) -> Vec> { + let addrs = self.ring.enqueue(trbs); + self.register_with_receiver(trbs, &addrs); + self.write_to_doorbell(); + self.get_trbs(trbs, &addrs).await + } + + fn register_with_receiver(&mut self, ts: &[transfer_trb::Allowed], addrs: &[PhysAddr]) { + for (t, addr) in ts.iter().zip(addrs) { + self.register_trb(t, *addr); + } + } + + fn register_trb(&mut self, t: &transfer_trb::Allowed, a: PhysAddr) { + if t.interrupt_on_completion() { + receiver::add_entry(a, self.waker.clone()).expect("Sender is already registered."); + } + } + + fn write_to_doorbell(&mut self) { + self.doorbell_writer.write(); + } + + async fn get_trbs( + &mut self, + ts: &[transfer_trb::Allowed], + addrs: &[PhysAddr], + ) -> Vec> { + let mut v = Vec::new(); + for (t, a) in ts.iter().zip(addrs) { + v.push(self.get_single_trb(t, *a).await); + } + v + } + + async fn get_single_trb( + &mut self, + t: &transfer_trb::Allowed, + addr: PhysAddr, + ) -> Option { + if t.interrupt_on_completion() { + Some(ReceiveFuture::new(addr, self.waker.clone()).await) + } else { + None + } + } +} + +pub(crate) struct DoorbellWriter { + slot_id: u8, + val: u32, +} +impl DoorbellWriter { + pub(crate) fn new(slot_id: u8, val: u32) -> Self { + Self { slot_id, val } + } + + pub(crate) fn write(&mut self) { + registers::handle(|r| { + r.doorbell.update_volatile_at(self.slot_id.into(), |d| { + d.set_doorbell_target(self.val.try_into().unwrap()); + }) + }); + } +} + +pub(crate) struct DescTyIdx { + ty: descriptor::Ty, + i: u8, +} +impl DescTyIdx { + pub(crate) fn new(ty: descriptor::Ty, i: u8) -> Self { + Self { ty, i } + } + pub(crate) fn bits(self) -> u16 { + (self.ty as u16) << 8 | u16::from(self.i) + } +} + +enum Request { + GetDescriptor = 6, +} diff --git a/test/src/main.rs b/test/src/main.rs index 33426f58..f3e1a617 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,54 +1,101 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + #![no_std] #![no_main] +// A workaround for the `derive_builder` crate. +#![allow(clippy::default_trait_access)] extern crate alloc; +use alloc::sync::Arc; +use futures_intrusive::sync::{GenericMutex, GenericMutexGuard}; +use multitask::{executor::Executor, task::Task}; +use pci::config::bar; +use qemu_exit::QEMUExit; +use qemu_print::qemu_println; +use spinning_top::{RawSpinlock, Spinlock}; +use structures::{ + dcbaa, extended_capabilities, registers, + ring::{command, event}, + scratchpad, +}; +use uefi::{ + table::{Boot, SystemTable}, + Handle, +}; +use x86_64::PhysAddr; + +pub(crate) type Futurelock = GenericMutex; +pub(crate) type FuturelockGuard<'a, T> = GenericMutexGuard<'a, RawSpinlock, T>; + mod allocator; -mod command_ring; -mod dcbaa; -mod event; +mod exchanger; mod mapper; +mod multitask; mod pci; -mod ports; -mod registers; -mod scratchpat; -mod transfer_ring; +mod port; +mod structures; +mod transition_helper; mod xhc; -use qemu_exit::QEMUExit; -use qemu_print::qemu_println; -use uefi::table::boot::MemoryType; - #[uefi::entry] -fn main(image: uefi::Handle, st: uefi::table::SystemTable) -> uefi::Status { - let (_, memory_map) = st.exit_boot_services(MemoryType::LOADER_DATA); - allocator::init(memory_map); +fn main(h: Handle, st: SystemTable) -> uefi::Status { + init(); + + let mut executor = Executor::new(); + executor.run(); +} + +pub(crate) fn init() { + if xhc::exists() { + init_and_spawn_tasks(); + } +} - registers::init(); +fn init_statics() { + let a = iter_xhc().next().expect("xHC does not exist."); + + // SAFETY: BAR 0 address is passed. + unsafe { + registers::init(a); + extended_capabilities::init(a); + } +} + +fn init_and_spawn_tasks() { + init_statics(); + + let mut event_ring = event::Ring::new(); + let command_ring = Arc::new(Spinlock::new(command::Ring::new())); xhc::init(); - let nop_addr = command_ring::send_nop(); + event_ring.init(); + command_ring.lock().init(); + dcbaa::init(); + scratchpad::init(); + exchanger::command::init(command_ring); - ports::init_all_ports(); + xhc::run(); + xhc::ensure_no_error_occurs(); - while let Some(trb) = event::dequeue() { - match trb { - Ok(xhci::ring::trb::event::Allowed::CommandCompletion(x)) => { - command_ring::process_trb(&x); - } - Ok(xhci::ring::trb::event::Allowed::PortStatusChange(x)) => { - ports::process_trb(&x); - } - Ok(x) => panic!("Unhandled TRB: {:?}", x), - Err(x) => panic!("Unknown TRB: {:?}", x), - } - } + spawn_tasks(event_ring); +} - command_ring::assert_all_trbs_are_processed(); +fn spawn_tasks(e: event::Ring) { + port::spawn_all_connected_port_tasks(); - let handler = qemu_exit::X86::new(0xf4, 33); - handler.exit_success(); + multitask::add(Task::new_poll(event::task(e))); +} + +fn iter_xhc() -> impl Iterator { + pci::iter_devices().filter_map(|device| { + if device.is_xhci() { + Some(device.base_address(bar::Index::new(0))) + } else { + None + } + }) } #[panic_handler] diff --git a/test/src/multitask/executor.rs b/test/src/multitask/executor.rs new file mode 100644 index 00000000..7cf2a87c --- /dev/null +++ b/test/src/multitask/executor.rs @@ -0,0 +1,79 @@ +// The MIT License (MIT) +// +// Copyright (c) 2019 Philipp Oppermann +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +use super::task; +use alloc::collections::BTreeMap; +use core::task::{Context, Poll, Waker}; +use task::Task; + +pub(crate) struct Executor { + waker_collection: BTreeMap, +} + +impl Executor { + pub(crate) fn new() -> Self { + Self { + waker_collection: BTreeMap::new(), + } + } + + pub(crate) fn run(&mut self) -> ! { + loop { + self.run_woken_tasks(); + } + } + + fn run_woken_tasks(&mut self) { + while let Some(id) = Self::pop_woken_task_id() { + self.run_task(id); + } + } + + fn pop_woken_task_id() -> Option { + task::COLLECTION.lock().pop_woken_task_id() + } + + fn run_task(&mut self, id: task::Id) { + let Self { + waker_collection: _, + } = self; + + let mut task = match task::COLLECTION.lock().remove_task(id) { + Some(task) => task, + None => return, + }; + + let mut context = self.generate_waker(id); + match task.poll(&mut context) { + Poll::Ready(_) => { + task::COLLECTION.lock().remove_task(id); + self.waker_collection.remove(&id); + } + Poll::Pending => Self::add_task_as_pending(task), + } + } + + fn generate_waker(&mut self, id: task::Id) -> Context<'_> { + let Self { waker_collection } = self; + + let waker = waker_collection + .entry(id) + .or_insert_with(|| task::COLLECTION.lock().create_waker(id)); + Context::from_waker(waker) + } + + fn add_task_as_pending(task: Task) { + if task.polling() { + task::COLLECTION.lock().add_task_as_woken(task); + } else { + task::COLLECTION.lock().add_task_as_sleep(task); + } + } +} diff --git a/test/src/multitask/mod.rs b/test/src/multitask/mod.rs new file mode 100644 index 00000000..5560a498 --- /dev/null +++ b/test/src/multitask/mod.rs @@ -0,0 +1,16 @@ +// The MIT License (MIT) +// +// Copyright (c) 2019 Philipp Oppermann +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +pub(crate) mod executor; +pub(crate) mod task; + +pub(crate) fn add(task: task::Task) { + task::COLLECTION.lock().add_task_as_woken(task); +} diff --git a/test/src/multitask/task.rs b/test/src/multitask/task.rs new file mode 100644 index 00000000..10caf388 --- /dev/null +++ b/test/src/multitask/task.rs @@ -0,0 +1,146 @@ +// The MIT License (MIT) +// +// Copyright (c) 2019 Philipp Oppermann +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake}; +use conquer_once::spin::Lazy; +use core::{ + future::Future, + pin::Pin, + sync::atomic::{AtomicU64, Ordering}, + task::{Context, Poll, Waker}, +}; +use crossbeam_queue::ArrayQueue; +use spinning_top::Spinlock; + +pub(super) static COLLECTION: Lazy> = + Lazy::new(|| Spinlock::new(Collection::new())); + +pub(crate) struct Collection { + tasks: BTreeMap, + woken_task_ids: Arc>, +} +impl Collection { + pub(crate) fn new() -> Self { + Self { + tasks: BTreeMap::new(), + woken_task_ids: Arc::new(ArrayQueue::new(100)), + } + } + + pub(crate) fn add_task_as_woken(&mut self, task: Task) { + let id = task.id(); + self.push_task(task); + self.push_woken_task_id(id); + } + + pub(crate) fn add_task_as_sleep(&mut self, task: Task) { + self.push_task(task); + } + + fn push_task(&mut self, task: Task) { + let id = task.id(); + if self.tasks.insert(id, task).is_some() { + panic!("Task ID confliction."); + } + } + + fn push_woken_task_id(&mut self, id: Id) { + self.woken_task_ids + .push(id) + .expect("Woken task id queue is full."); + } + + pub(crate) fn pop_woken_task_id(&mut self) -> Option { + self.woken_task_ids.pop() + } + + pub(crate) fn remove_task(&mut self, id: Id) -> Option { + self.tasks.remove(&id) + } + + pub(crate) fn create_waker(&mut self, id: Id) -> Waker { + Waker::from(Arc::new(TaskWaker::new(id, self.woken_task_ids.clone()))) + } +} + +// task::Waker conflicts with alloc::task::Waker. +#[allow(clippy::module_name_repetitions)] +pub(crate) struct TaskWaker { + id: Id, + woken_task_ids: Arc>, +} + +impl TaskWaker { + pub(crate) fn new(id: Id, woken_task_ids: Arc>) -> Self { + Self { id, woken_task_ids } + } + + fn wake_task(&self) { + self.woken_task_ids + .push(self.id) + .expect("task_queue is full"); + } +} + +impl Wake for TaskWaker { + fn wake(self: Arc) { + self.wake_task(); + } + + fn wake_by_ref(self: &Arc) { + self.wake_task() + } +} + +#[derive(PartialOrd, PartialEq, Ord, Eq, Copy, Clone, Debug)] +pub(crate) struct Id(u64); + +impl Id { + fn new() -> Self { + static NEXT_ID: AtomicU64 = AtomicU64::new(0); + Id(NEXT_ID.fetch_add(1, Ordering::Relaxed)) + } +} + +pub(crate) struct Task { + id: Id, + future: Pin + Send>>, + polling: bool, +} + +impl Task { + pub(crate) fn new(future: impl Future + 'static + Send) -> Self { + Self { + id: Id::new(), + future: Box::pin(future), + polling: false, + } + } + + pub(crate) fn new_poll(future: impl Future + 'static + Send) -> Self { + Self { + id: Id::new(), + future: Box::pin(future), + polling: true, + } + } + + pub(crate) fn poll(&mut self, context: &mut Context<'_>) -> Poll<()> { + self.future.as_mut().poll(context) + } + + pub(crate) fn polling(&self) -> bool { + self.polling + } + + pub(super) fn id(&self) -> Id { + self.id + } +} diff --git a/test/src/pci.rs b/test/src/pci.rs deleted file mode 100644 index 862a7550..00000000 --- a/test/src/pci.rs +++ /dev/null @@ -1,149 +0,0 @@ -use bit_field::BitField; -use x86_64::instructions::port::PortRead; -use x86_64::instructions::port::PortWrite; - -pub fn iter_xhc() -> impl Iterator { - iter_devices().filter(|device| { - // The base class, sub class, and interface are defined in [1]. - // - // [1] eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2 Table 5-4 - device.base_class() == 0x0c && device.sub_class() == 0x03 && device.interface() == 0x30 - }) -} - -fn iter_devices() -> impl Iterator { - DeviceIter::new() -} - -struct DeviceIter { - device: u8, - bus: u8, -} -impl DeviceIter { - fn new() -> Self { - Self { device: 0, bus: 0 } - } -} -impl Iterator for DeviceIter { - type Item = ConfigSpace; - - fn next(&mut self) -> Option { - if self.device == 32 { - self.device = 0; - - let Some(result) = self.bus.checked_add(1) else { - return None; - }; - - self.bus = result; - } - - let config_address_reader = unsafe { ConfigSpaceReader::new(0, self.device, self.bus) }; - let config_space = unsafe { ConfigSpace::new(config_address_reader) }; - - self.device += 1; - - if config_space.vendor_id() == 0xffff { - return self.next(); - } - - Some(config_space) - } -} - -pub struct ConfigSpace { - address: ConfigSpaceReader, -} -impl ConfigSpace { - /// # Safety - /// - /// `address` must be a valid address. - unsafe fn new(address: ConfigSpaceReader) -> Self { - Self { address } - } - - // See [1] for the structure of the PCI configuration space for xHCI. - // - // [1]: eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2 Figure 5-1. - - pub fn base_address_register(&self, index: u8) -> u32 { - assert!(index < 6, "index must be less than 6"); - - let result = unsafe { self.address.read(4 + index) }; - - result - } - - fn vendor_id(&self) -> u16 { - let result = unsafe { self.address.read(0) }; - - result.get_bits(0..=15) as u16 - } - - fn base_class(&self) -> u8 { - let result = unsafe { self.address.read(2) }; - - result.get_bits(24..=31) as u8 - } - - fn sub_class(&self) -> u8 { - let result = unsafe { self.address.read(2) }; - - result.get_bits(16..=23) as u8 - } - - fn interface(&self) -> u8 { - let result = unsafe { self.address.read(2) }; - - result.get_bits(8..=15) as u8 - } -} - -struct ConfigSpaceReader { - function: u8, - device: u8, - bus: u8, -} -impl ConfigSpaceReader { - const CONFIG_ADDRESS: u16 = 0xcf8; - const CONFIG_DATA: u16 = 0xcfc; - - /// # Safety - /// - /// `function`, `device`, and `bus` must be valid. - unsafe fn new(function: u8, device: u8, bus: u8) -> Self { - assert!(function < 8, "function must be less than 8"); - assert!(device < 32, "device must be less than 32"); - - Self { - function, - device, - bus, - } - } - - unsafe fn read(&self, offset: u8) -> u32 { - assert!(offset < 32, "offset must be less than 32"); - - // The method of how to read values from the PCI configuration space is described in [1]. - // - // [1]: https://wiki.osdev.org/PCI#Configuration_Space - unsafe { PortWrite::write_to_port(Self::CONFIG_ADDRESS, self.config_addr(offset)) }; - unsafe { PortRead::read_from_port(Self::CONFIG_DATA) } - } - - // See [1] for the description of bits in the PCI configuration address. - // - // [1]: https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231 - fn config_addr(&self, offset: u8) -> u32 { - let mut result = 0; - - result.set_bits(2..=7, offset.into()); - result.set_bits(8..=10, self.function.into()); - result.set_bits(11..=15, self.device.into()); - result.set_bits(16..=23, self.bus.into()); - result.set_bit(31, true); - - result - } -} diff --git a/test/src/pci/config/bar.rs b/test/src/pci/config/bar.rs new file mode 100644 index 00000000..dfdfd677 --- /dev/null +++ b/test/src/pci/config/bar.rs @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::RegisterIndex; +use core::{ + convert::{From, TryFrom}, + ops::Add, +}; +use x86_64::PhysAddr; + +#[derive(Debug, Copy, Clone, Default)] +pub(crate) struct Bar(u32); + +impl Bar { + pub(crate) fn new(bar: u32) -> Self { + Self(bar) + } + + pub(crate) fn base_addr(self, upper: Option) -> Option { + match upper { + Some(upper) => match self.ty() { + BarType::Bar64Bit => self.base_addr_64(upper), + BarType::Bar32Bit => self.base_addr_32(), + }, + None => self.base_addr_32(), + } + } + + fn ty(self) -> BarType { + let ty_raw = (self.0 >> 1) & 0b11; + if ty_raw == 0 { + BarType::Bar32Bit + } else if ty_raw == 0x02 { + BarType::Bar64Bit + } else { + unreachable!(); + } + } + + fn base_addr_64(self, upper: Bar) -> Option { + match self.ty() { + BarType::Bar32Bit => None, + BarType::Bar64Bit => Some(PhysAddr::new( + (u64::from(self.0 & !0xf)) | ((u64::from(upper.0)) << 32), + )), + } + } + + fn base_addr_32(self) -> Option { + match self.ty() { + BarType::Bar32Bit => Some(PhysAddr::new(u64::from(self.0 & !0xf))), + BarType::Bar64Bit => None, + } + } +} + +#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq)] +pub(crate) struct Index(u32); +impl Index { + pub(crate) fn new(index: u32) -> Self { + assert!(index < 6); + Self(index) + } +} +impl From for RegisterIndex { + fn from(bar_index: Index) -> Self { + RegisterIndex::new(usize::try_from(bar_index.0 + 4).unwrap()) + } +} +impl Add for Index { + type Output = Self; + + fn add(self, rhs: u32) -> Self::Output { + Self::new(self.0 + rhs) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub(super) enum BarType { + Bar32Bit, + Bar64Bit, +} diff --git a/test/src/pci/config/common.rs b/test/src/pci/config/common.rs new file mode 100644 index 00000000..274ec347 --- /dev/null +++ b/test/src/pci/config/common.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::{RegisterIndex, Registers}; +use bit_field::BitField; +use core::convert::{TryFrom, TryInto}; + +#[derive(Debug)] +pub(super) struct Common<'a> { + registers: &'a Registers, +} +impl<'a> Common<'a> { + pub(super) fn new(registers: &'a Registers) -> Self { + Self { registers } + } + + pub(super) fn is_xhci(&self) -> bool { + self.class().is_xhci() + } + + pub(super) fn bridge_type(&self) -> BridgeType { + self.header_type().bridge_type() + } + + fn class(&self) -> Class<'_> { + Class::new(self.registers) + } + + fn header_type(&self) -> HeaderType { + HeaderType::new(self.registers) + } +} + +#[derive(Debug, Copy, Clone)] +struct HeaderType(u8); +impl HeaderType { + fn new(register: &Registers) -> Self { + let header = u8::try_from((register.get(RegisterIndex::new(3)) >> 16) & 0xff).unwrap(); + + Self(header) + } + + fn bridge_type(self) -> BridgeType { + match self.0 & 0x7f { + 0 => BridgeType::NonBridge, + 1 => BridgeType::PciToPci, + 2 => BridgeType::PciToCardbus, + _ => unreachable!(), + } + } +} + +#[derive(Debug)] +pub(super) enum BridgeType { + NonBridge, + PciToPci, + PciToCardbus, +} + +#[derive(Debug)] +struct Class<'a> { + registers: &'a Registers, +} +impl<'a> Class<'a> { + fn new(registers: &'a Registers) -> Self { + Self { registers } + } + + fn is_xhci(&self) -> bool { + self.as_tuple() == (0x0c, 0x03, 0x30) + } + + fn as_tuple(&self) -> (u8, u8, u8) { + (self.base(), self.sub(), self.interface()) + } + + fn base(&self) -> u8 { + self.raw().get_bits(24..=31).try_into().unwrap() + } + + fn sub(&self) -> u8 { + self.raw().get_bits(16..=23).try_into().unwrap() + } + + fn interface(&self) -> u8 { + self.raw().get_bits(8..=15).try_into().unwrap() + } + + fn raw(&self) -> u32 { + self.registers.get(RegisterIndex::new(2)) + } +} diff --git a/test/src/pci/config/mod.rs b/test/src/pci/config/mod.rs new file mode 100644 index 00000000..dec4b6f1 --- /dev/null +++ b/test/src/pci/config/mod.rs @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub(crate) mod bar; +mod common; +pub(crate) mod type_spec; + +use self::common::Common; +use bar::Bar; +use core::{convert::TryFrom, ops::Add}; +use type_spec::TypeSpec; +use x86_64::{ + structures::port::{PortRead, PortWrite}, + PhysAddr, +}; + +#[derive(Debug)] +pub(crate) struct Space { + registers: Registers, +} + +impl Space { + pub(crate) fn new(bus: Bus, device: Device) -> Option { + Some(Self { + registers: Registers::new(bus, device)?, + }) + } + + pub(crate) fn is_xhci(&self) -> bool { + self.common().is_xhci() + } + + pub(crate) fn base_address(&self, index: bar::Index) -> PhysAddr { + self.type_spec().base_address(index) + } + + fn type_spec(&self) -> TypeSpec<'_> { + TypeSpec::new(&self.registers, &self.common()) + } + + fn common(&self) -> Common<'_> { + Common::new(&self.registers) + } +} + +#[derive(Debug)] +pub(crate) struct Registers { + bus: Bus, + device: Device, +} +impl Registers { + fn new(bus: Bus, device: Device) -> Option { + if Self::valid(bus, device) { + Some(Self { bus, device }) + } else { + None + } + } + + fn valid(bus: Bus, device: Device) -> bool { + let config_addr = ConfigAddress::new(bus, device, Function::zero(), RegisterIndex::zero()); + let id = unsafe { config_addr.read() }; + + id != !0 + } + + fn get(&self, index: RegisterIndex) -> u32 { + let accessor = ConfigAddress::new(self.bus, self.device, Function::zero(), index); + unsafe { accessor.read() } + } +} + +struct ConfigAddress { + bus: Bus, + device: Device, + function: Function, + register: RegisterIndex, +} + +impl ConfigAddress { + const PORT_CONFIG_ADDR: u16 = 0xcf8; + const PORT_CONFIG_DATA: u16 = 0xcfc; + + #[allow(clippy::too_many_arguments)] + fn new(bus: Bus, device: Device, function: Function, register: RegisterIndex) -> Self { + Self { + bus, + device, + function, + register, + } + } + + fn as_u32(&self) -> u32 { + const VALID: u32 = 0x8000_0000; + let bus = self.bus.as_u32(); + let device = self.device.as_u32(); + let function = self.function.as_u32(); + let register = u32::try_from(self.register.as_usize()).unwrap(); + + VALID | bus << 16 | device << 11 | function << 8 | register << 2 + } + + /// SAFETY: `self` must contain the valid config address. + unsafe fn read(&self) -> u32 { + PortWrite::write_to_port(Self::PORT_CONFIG_ADDR, self.as_u32()); + PortRead::read_from_port(Self::PORT_CONFIG_DATA) + } +} + +#[derive(Copy, Clone, Debug)] +pub(crate) struct Bus(u32); +impl Bus { + pub(crate) const MAX: u32 = 256; + pub(crate) fn new(bus: u32) -> Self { + assert!(bus < Self::MAX); + Self(bus) + } + + fn as_u32(self) -> u32 { + self.0 + } +} + +#[derive(Copy, Clone, Debug)] +pub(crate) struct Device(u32); +impl Device { + pub(crate) const MAX: u32 = 32; + pub(crate) fn new(device: u32) -> Self { + assert!(device < Self::MAX); + Self(device) + } + + fn as_u32(self) -> u32 { + self.0 + } +} + +#[derive(Copy, Clone)] +pub(crate) struct Function(u32); +impl Function { + pub(crate) fn zero() -> Self { + Self(0) + } + + pub(crate) fn as_u32(self) -> u32 { + self.0 + } +} + +#[derive(Debug, Copy, Clone)] +pub(crate) struct RegisterIndex(usize); +impl RegisterIndex { + const MAX: usize = 64; + pub(crate) fn new(offset: usize) -> Self { + assert!(offset < Self::MAX, "Too large register index: {}", offset); + Self(offset) + } + + fn zero() -> Self { + Self(0) + } + + fn as_usize(self) -> usize { + self.0 + } +} + +impl Add for RegisterIndex { + type Output = RegisterIndex; + + fn add(self, rhs: usize) -> Self::Output { + Self(self.0 + rhs) + } +} diff --git a/test/src/pci/config/type_spec/mod.rs b/test/src/pci/config/type_spec/mod.rs new file mode 100644 index 00000000..abf4555e --- /dev/null +++ b/test/src/pci/config/type_spec/mod.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +mod non_bridge; + +use super::{ + bar, + common::{BridgeType, Common}, + Bar, RegisterIndex, Registers, +}; +use x86_64::PhysAddr; + +#[derive(Debug)] +pub(super) enum TypeSpec<'a> { + NonBridge(non_bridge::TypeSpec<'a>), +} + +impl<'a> TypeSpec<'a> { + pub(super) fn new(registers: &'a Registers, common: &Common<'_>) -> Self { + match common.bridge_type() { + BridgeType::NonBridge => TypeSpec::NonBridge(non_bridge::TypeSpec::new(registers)), + e => panic!("Not implemented: {:?}\ncommon:{:?}", e, common), + } + } + + pub(super) fn base_address(&self, index: bar::Index) -> PhysAddr { + let TypeSpec::NonBridge(non_bridge) = self; + non_bridge.base_addr(index) + } +} diff --git a/test/src/pci/config/type_spec/non_bridge.rs b/test/src/pci/config/type_spec/non_bridge.rs new file mode 100644 index 00000000..27e3cac3 --- /dev/null +++ b/test/src/pci/config/type_spec/non_bridge.rs @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::{bar, Bar, RegisterIndex, Registers}; +use log::debug; +use x86_64::PhysAddr; + +#[derive(Debug)] +pub(crate) struct TypeSpec<'a> { + registers: &'a Registers, +} + +impl<'a> TypeSpec<'a> { + pub(crate) fn new(registers: &'a Registers) -> Self { + Self { registers } + } + + pub(crate) fn base_addr(&self, index: bar::Index) -> PhysAddr { + let upper = if index == bar::Index::new(5) { + None + } else { + Some(self.bar(index + 1)) + }; + + for i in 0..6 { + debug!("Bar{}: {:?}", i, self.bar(bar::Index::new(i))); + } + + self.bar(index) + .base_addr(upper) + .expect("Could not calculate Base Address.") + } + + fn bar(&self, index: bar::Index) -> Bar { + Bar::new(self.registers.get(RegisterIndex::from(index))) + } +} diff --git a/test/src/pci/mod.rs b/test/src/pci/mod.rs new file mode 100644 index 00000000..3621b8a1 --- /dev/null +++ b/test/src/pci/mod.rs @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub(crate) mod config; + +use config::{Bus, Device}; + +pub(crate) fn iter_devices() -> impl Iterator { + IterPciDevices::new(0, 0) +} + +struct IterPciDevices { + bus: u32, + device: u32, +} + +impl IterPciDevices { + fn new(bus: u32, device: u32) -> Self { + assert!(device < 32); + Self { bus, device } + } +} + +impl Iterator for IterPciDevices { + type Item = config::Space; + + fn next(&mut self) -> Option { + for bus in self.bus..Bus::MAX { + for device in self.device..Device::MAX { + if let Some(space) = config::Space::new(Bus::new(bus), Device::new(device)) { + self.bus = bus; + self.device = device + 1; + + return Some(space); + } + } + + self.device = 0; + } + + None + } +} diff --git a/test/src/port/class_driver/keyboard.rs b/test/src/port/class_driver/keyboard.rs new file mode 100644 index 00000000..c6948252 --- /dev/null +++ b/test/src/port/class_driver/keyboard.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::{ + port::init::fully_operational::FullyOperational, + structures::descriptor::{Configuration, Descriptor}, + transition_helper::BoxWrapper, +}; +use alloc::{string::String, vec::Vec}; +use log::info; +use spinning_top::Spinlock; +use xhci::context::EndpointType; + +const LOWER_ALPHABETS: &str = "abcdefghijklmnopqrstuvwxyz"; + +static STR: Spinlock = Spinlock::new(String::new()); + +pub(in crate::port) async fn task(eps: FullyOperational) { + let mut k = Keyboard::new(eps); + k.configure().await; + + info!("Set the Boot protocol."); + k.set_boot_protocol().await; + info!("Set."); + + loop { + k.get_packet().await; + k.store_key(); + } +} + +pub(crate) struct Keyboard { + ep: FullyOperational, + buf: BoxWrapper<[u8; 8]>, +} +impl Keyboard { + pub(in crate::port) fn new(ep: FullyOperational) -> Self { + Self { + ep, + buf: [0; 8].into(), + } + } + + async fn configure(&mut self) { + let d = self.configuration_descriptor(); + self.ep.set_configure(d.config_val()).await; + } + + async fn set_boot_protocol(&mut self) { + self.ep.set_boot_protocol().await; + } + + async fn get_packet(&mut self) { + self.issue_normal_trb().await; + } + + async fn issue_normal_trb(&mut self) { + self.ep + .issue_normal_trb(&self.buf, EndpointType::InterruptIn) + .await + .expect("Failed to send a Normal TRB"); + } + + fn configuration_descriptor(&self) -> Configuration { + *self + .ep + .descriptors() + .iter() + .filter_map(|x| { + if let Descriptor::Configuration(c) = x { + Some(c) + } else { + None + } + }) + .collect::>()[0] + } + + fn store_key(&self) { + for c in self.buf.iter().skip(2) { + if *c >= 4 && *c <= 0x1d { + STR.lock() + .push(LOWER_ALPHABETS.chars().nth((c - 4).into()).unwrap()); + } else if *c == 0x28 { + info!("{}", STR.lock()); + *STR.lock() = String::new(); + } + } + } +} diff --git a/test/src/port/class_driver/mass_storage/mod.rs b/test/src/port/class_driver/mass_storage/mod.rs new file mode 100644 index 00000000..54bd7ed4 --- /dev/null +++ b/test/src/port/class_driver/mass_storage/mod.rs @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +mod scsi; + +use crate::{ + port::init::fully_operational::FullyOperational, + structures::descriptor::{Configuration, Descriptor}, + transition_helper::BoxWrapper, +}; +use alloc::vec::Vec; +use log::info; +use scsi::{ + command_data_block, + response::{Inquiry, Read10, ReadCapacity10}, + CommandBlockWrapper, CommandBlockWrapperHeaderBuilder, CommandStatusWrapper, +}; +use xhci::context::EndpointType; + +pub(in crate::port) async fn task(eps: FullyOperational) { + let mut m = MassStorage::new(eps); + info!("This is the task of USB Mass Storage."); + + m.configure().await; + info!("USB Mass Storage is configured."); + + let b = m.inquiry().await; + info!("Inquiry Command: {:?}", b); + + let b = m.read_capacity_10().await; + info!("Read Capacity: {:?}", b); + + m.read10().await; + + m.write10().await; +} + +struct MassStorage { + ep: FullyOperational, +} +impl MassStorage { + fn new(ep: FullyOperational) -> Self { + Self { ep } + } + + async fn configure(&mut self) { + let d = self.configuration_descriptor(); + self.ep.set_configure(d.config_val()).await; + } + + fn configuration_descriptor(&self) -> Configuration { + *self + .ep + .descriptors() + .iter() + .filter_map(|x| { + if let Descriptor::Configuration(c) = x { + Some(c) + } else { + None + } + }) + .collect::>()[0] + } + + async fn inquiry(&mut self) -> Inquiry { + const LEN: u16 = 0x24; + + let header = CommandBlockWrapperHeaderBuilder::default() + .transfer_length(LEN.into()) + .flags(scsi::Flags::In) + .lun(0) + .command_len(6) + .build() + .expect("Failed to build an inquiry command block wrapper."); + let data = command_data_block::Inquiry::new(LEN); + let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + + let (response, status): (BoxWrapper, _) = + self.send_scsi_command(&mut wrapper).await; + + status.check_corruption(); + *response + } + + async fn read_capacity_10(&mut self) -> ReadCapacity10 { + let header = CommandBlockWrapperHeaderBuilder::default() + .transfer_length(8) + .flags(scsi::Flags::In) + .lun(0) + .command_len(10) + .build() + .expect("Failed to build a read capacity command block wrapper"); + let data = command_data_block::ReadCapacity::default(); + let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + + let (response, status): (BoxWrapper, _) = + self.send_scsi_command(&mut wrapper).await; + + status.check_corruption(); + *response + } + + async fn read10(&mut self) -> BoxWrapper { + let header = CommandBlockWrapperHeaderBuilder::default() + .transfer_length(0x8000) + .flags(scsi::Flags::In) + .lun(0) + .command_len(0x0a) + .build() + .expect("Failed to build a read 10 command block wrapper."); + let data = command_data_block::Read10::new(0, 64); + let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + + let (response, status): (BoxWrapper, _) = + self.send_scsi_command(&mut wrapper).await; + + status.check_corruption(); + response + } + + async fn write10(&mut self) { + let header = CommandBlockWrapperHeaderBuilder::default() + .transfer_length(0x0008) + .flags(scsi::Flags::Out) + .lun(0) + .command_len(0x0a) + .build() + .expect("Failed to build a write 10 command block wrapper."); + let data = command_data_block::Write10::new(0, 64); + let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + + let content = BoxWrapper::from(0x334_usize); + + let status = self.send_scsi_command_for_out(&mut wrapper, &content).await; + status.check_corruption(); + } + + async fn send_scsi_command( + &mut self, + c: &mut BoxWrapper, + ) -> (BoxWrapper, BoxWrapper) + where + T: Default, + { + self.send_command_block_wrapper(c).await; + let response = self.receive_command_response().await; + let status = self.receive_command_status().await; + (response, status) + } + + async fn send_scsi_command_for_out( + &mut self, + c: &mut BoxWrapper, + d: &BoxWrapper, + ) -> BoxWrapper { + self.send_command_block_wrapper(c).await; + self.send_additional_data(d).await; + self.receive_command_status().await + } + + async fn send_command_block_wrapper(&mut self, c: &mut BoxWrapper) { + self.ep + .issue_normal_trb(c, EndpointType::BulkOut) + .await + .expect("Failed to send a SCSI command."); + } + + async fn receive_command_response(&mut self) -> BoxWrapper + where + T: Default, + { + let c = BoxWrapper::default(); + self.ep + .issue_normal_trb(&c, EndpointType::BulkIn) + .await + .expect("Failed to receive a SCSI command reponse."); + c + } + + async fn send_additional_data(&mut self, d: &BoxWrapper) { + self.ep + .issue_normal_trb(d, EndpointType::BulkOut) + .await + .expect("Failed to send a data."); + } + + async fn receive_command_status(&mut self) -> BoxWrapper { + let b = BoxWrapper::default(); + self.ep + .issue_normal_trb(&b, EndpointType::BulkIn) + .await + .expect("Failed to receive a SCSI status."); + b + } +} diff --git a/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs b/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs new file mode 100644 index 00000000..16d8a765 --- /dev/null +++ b/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use byteorder::{BigEndian, ByteOrder}; + +#[derive(Copy, Clone)] +pub(in super::super) enum CommandDataBlock { + Inquiry(Inquiry), + ReadCapacity(ReadCapacity), + Read10(Read10), + Write10(Write10), +} +impl From for [u8; 16] { + fn from(cdb: CommandDataBlock) -> Self { + match cdb { + CommandDataBlock::Inquiry(i) => i.0, + CommandDataBlock::ReadCapacity(r) => r.0, + CommandDataBlock::Read10(r) => r.0, + CommandDataBlock::Write10(w) => w.0, + } + } +} + +macro_rules! command { + ($name:ident) => { + #[derive(Copy, Clone)] + pub(in super::super) struct $name([u8; 16]); + impl $name { + fn set_command(&mut self) -> &mut Self { + self.0[0] = Command::$name.into(); + self + } + } + impl Default for $name { + fn default() -> Self { + *Self([0; 16]).set_command() + } + } + impl From<$name> for CommandDataBlock { + fn from(c: $name) -> CommandDataBlock { + CommandDataBlock::$name(c) + } + } + }; +} + +command!(Inquiry); +impl Inquiry { + pub(in super::super) fn new(length: u16) -> Self { + *Self::default().set_length(length) + } + + fn set_length(&mut self, l: u16) -> &mut Self { + BigEndian::write_u16(&mut self.0[3..=4], l); + self + } +} + +command!(ReadCapacity); + +command!(Read10); +impl Read10 { + pub(in super::super) fn new(lba: u32, num_of_blocks: u16) -> Self { + *Self::default() + .set_lba(lba) + .set_num_of_blocks(num_of_blocks) + } + + fn set_lba(&mut self, l: u32) -> &mut Self { + BigEndian::write_u32(&mut self.0[2..6], l); + self + } + + fn set_num_of_blocks(&mut self, n: u16) -> &mut Self { + BigEndian::write_u16(&mut self.0[7..=8], n); + self + } +} + +command!(Write10); +impl Write10 { + pub(in super::super) fn new(lba: u32, num_of_blocks: u16) -> Self { + *Self::default() + .set_lba(lba) + .set_num_of_blocks(num_of_blocks) + } + + fn set_lba(&mut self, l: u32) -> &mut Self { + BigEndian::write_u32(&mut self.0[2..6], l); + self + } + + fn set_num_of_blocks(&mut self, n: u16) -> &mut Self { + BigEndian::write_u16(&mut self.0[7..=8], n); + self + } +} + +#[repr(u8)] +enum Command { + Inquiry = 0x12, + ReadCapacity = 0x25, + Read10 = 0x28, + Write10 = 0x2a, +} +impl From for u8 { + fn from(c: Command) -> Self { + c as u8 + } +} diff --git a/test/src/port/class_driver/mass_storage/scsi/mod.rs b/test/src/port/class_driver/mass_storage/scsi/mod.rs new file mode 100644 index 00000000..e55e887d --- /dev/null +++ b/test/src/port/class_driver/mass_storage/scsi/mod.rs @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub(super) mod command_data_block; +pub(super) mod response; + +use command_data_block::CommandDataBlock; +use derive_builder::Builder; +use num_derive::FromPrimitive; + +#[repr(C, packed)] +pub(super) struct CommandBlockWrapper { + header: CommandBlockWrapperHeader, + data: [u8; 16], +} +impl CommandBlockWrapper { + pub(super) fn new(header: CommandBlockWrapperHeader, data: CommandDataBlock) -> Self { + Self { + header, + data: data.into(), + } + } +} + +#[repr(C, packed)] +#[derive(Builder)] +#[builder(no_std)] +pub(super) struct CommandBlockWrapperHeader { + #[builder(default = "CommandBlockWrapperHeader::SIGNATURE")] + signature: u32, + #[builder(default = "0")] + tag: u32, + transfer_length: u32, + flags: Flags, + lun: u8, + command_len: u8, +} +impl CommandBlockWrapperHeader { + const SIGNATURE: u32 = 0x4342_5355; +} + +#[repr(u8)] +#[derive(Copy, Clone)] +pub(super) enum Flags { + Out = 0, + In = 0x80, +} + +#[repr(C, packed)] +#[derive(Copy, Clone, Default)] +pub(super) struct CommandStatusWrapper { + signature: u32, + tag: u32, + data_residue: u32, + status: u8, +} +impl CommandStatusWrapper { + pub(super) fn check_corruption(&self) { + const USBS: u32 = 0x5342_5355; + let signature = self.signature; + + assert_eq!( + signature, USBS, + "The signature of the Command Status Wrapper is wrong." + ); + } +} + +#[derive(Copy, Clone, Debug, FromPrimitive)] +pub(super) enum Status { + Good = 0, +} +impl Default for Status { + fn default() -> Self { + Self::Good + } +} diff --git a/test/src/port/class_driver/mass_storage/scsi/response.rs b/test/src/port/class_driver/mass_storage/scsi/response.rs new file mode 100644 index 00000000..a753b02e --- /dev/null +++ b/test/src/port/class_driver/mass_storage/scsi/response.rs @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use byteorder::{BigEndian, ByteOrder}; +use core::fmt; + +#[derive(Copy, Clone, Debug)] +#[repr(transparent)] +pub(crate) struct Inquiry([u8; 36]); +impl Default for Inquiry { + fn default() -> Self { + Self([0; 36]) + } +} + +#[derive(Copy, Clone, Default)] +#[repr(C)] +pub(crate) struct ReadCapacity10 { + lba: [u8; 4], + block_size: [u8; 4], +} +impl ReadCapacity10 { + fn lba(self) -> u32 { + BigEndian::read_u32(&self.lba) + } + + fn block_size(self) -> u32 { + BigEndian::read_u32(&self.block_size) + } +} +impl fmt::Debug for ReadCapacity10 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ReadCapacity10") + .field("lba", &self.lba()) + .field("block_size", &self.block_size()) + .finish() + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(transparent)] +pub(crate) struct Read10([u8; 32768]); +impl Default for Read10 { + fn default() -> Self { + Self([0; 32768]) + } +} diff --git a/test/src/port/class_driver/mod.rs b/test/src/port/class_driver/mod.rs new file mode 100644 index 00000000..74bb09e5 --- /dev/null +++ b/test/src/port/class_driver/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub(crate) mod keyboard; +pub(super) mod mass_storage; +pub(crate) mod mouse; diff --git a/test/src/port/class_driver/mouse.rs b/test/src/port/class_driver/mouse.rs new file mode 100644 index 00000000..110e61fd --- /dev/null +++ b/test/src/port/class_driver/mouse.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::{ + port::init::fully_operational::FullyOperational, + structures::descriptor::{Configuration, Descriptor}, + transition_helper::BoxWrapper, +}; +use alloc::vec::Vec; +use log::info; +use xhci::context::EndpointType; + +pub(in super::super) async fn task(eps: FullyOperational) { + let mut m = Mouse::new(eps); + + m.configure().await; + info!("Configuration completed."); + + m.set_boot_protocol().await; + info!("Boot protocol is set."); + + m.set_idle().await; + info!("Set Idle completed."); + + loop { + m.get_packet().await; + m.print_buf(); + } +} + +pub(crate) struct Mouse { + ep: FullyOperational, + buf: BoxWrapper<[i8; 4]>, +} +impl Mouse { + pub(super) fn new(ep: FullyOperational) -> Self { + Self { + ep, + buf: [0; 4].into(), + } + } + + async fn configure(&mut self) { + let d = self.configuration_descriptor(); + self.ep.set_configure(d.config_val()).await; + } + + async fn set_idle(&mut self) { + self.ep.set_idle().await; + } + + async fn set_boot_protocol(&mut self) { + self.ep.set_boot_protocol().await; + } + + fn configuration_descriptor(&self) -> Configuration { + *self + .ep + .descriptors() + .iter() + .filter_map(|x| { + if let Descriptor::Configuration(c) = x { + Some(c) + } else { + None + } + }) + .collect::>()[0] + } + + async fn get_packet(&mut self) { + self.issue_normal_trb().await; + } + + async fn issue_normal_trb(&mut self) { + self.ep + .issue_normal_trb(&self.buf, EndpointType::InterruptIn) + .await + .expect("Failed to send a Normal TRB."); + } + + fn print_buf(&self) { + info!( + "Button: {} {} {}, X: {}, Y: {}", + self.buf[0] & 1 == 1, + self.buf[0] & 2 == 2, + self.buf[0] & 4 == 4, + self.buf[1], + self.buf[2] + ); + } +} diff --git a/test/src/port/endpoint.rs b/test/src/port/endpoint.rs new file mode 100644 index 00000000..d9e1e7f6 --- /dev/null +++ b/test/src/port/endpoint.rs @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::{exchanger::transfer, structures::descriptor, transition_helper::BoxWrapper}; +use x86_64::PhysAddr; +use xhci::context::EndpointType; + +pub(super) struct Default { + sender: transfer::Sender, +} +impl Default { + pub(super) fn new(sender: transfer::Sender) -> Self { + Self { sender } + } + + pub(super) fn ring_addr(&self) -> PhysAddr { + self.sender.ring_addr() + } + + pub(super) async fn get_max_packet_size(&mut self) -> u16 { + self.sender + .get_max_packet_size_from_device_descriptor() + .await + } + + pub(super) async fn get_raw_configuration_descriptors(&mut self) -> BoxWrapper<[u8]> { + self.sender.get_configuration_descriptor().await + } + + pub(super) async fn set_configuration(&mut self, config_val: u8) { + self.sender.set_configure(config_val).await; + } + + pub(super) async fn set_idle(&mut self) { + self.sender.set_idle().await; + } + + pub(super) async fn set_boot_protocol(&mut self) { + self.sender.set_boot_protocol().await; + } +} + +pub(super) struct NonDefault { + desc: descriptor::Endpoint, + sender: transfer::Sender, +} +impl NonDefault { + pub(super) fn new(desc: descriptor::Endpoint, sender: transfer::Sender) -> Self { + Self { desc, sender } + } + + pub(super) fn descriptor(&self) -> descriptor::Endpoint { + self.desc + } + + pub(super) fn transfer_ring_addr(&self) -> PhysAddr { + self.sender.ring_addr() + } + + pub(super) fn ty(&self) -> EndpointType { + self.desc.ty() + } + + pub(super) async fn issue_normal_trb(&mut self, b: &BoxWrapper) { + self.sender.issue_normal_trb(b).await + } +} + +#[derive(Debug)] +pub(crate) enum Error { + NoSuchEndpoint(EndpointType), +} diff --git a/test/src/port/init/descriptor_fetcher.rs b/test/src/port/init/descriptor_fetcher.rs new file mode 100644 index 00000000..e97a3568 --- /dev/null +++ b/test/src/port/init/descriptor_fetcher.rs @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::{ + endpoints_initializer::EndpointsInitializer, max_packet_size_setter::MaxPacketSizeSetter, +}; +use crate::{ + port::endpoint, + structures::{context::Context, descriptor, descriptor::Descriptor}, + transition_helper::BoxWrapper, +}; +use alloc::{sync::Arc, vec::Vec}; +use log::debug; +use spinning_top::Spinlock; + +pub(super) struct DescriptorFetcher { + port_number: u8, + slot_number: u8, + cx: Arc>, + ep0: endpoint::Default, +} +impl DescriptorFetcher { + pub(super) fn new(s: MaxPacketSizeSetter) -> Self { + let port_number = s.port_number(); + let slot_number = s.slot_number(); + let cx = s.context(); + let ep0 = s.ep0(); + + Self { + port_number, + slot_number, + cx, + ep0, + } + } + + pub(super) async fn fetch(mut self) -> EndpointsInitializer { + let r = self.get_raw_descriptors().await; + let ds = RawDescriptorParser::new(r).parse(); + EndpointsInitializer::new(self, ds) + } + + pub(super) fn context(&self) -> Arc> { + self.cx.clone() + } + + pub(super) fn port_number(&self) -> u8 { + self.port_number + } + + pub(super) fn slot_number(&self) -> u8 { + self.slot_number + } + + pub(super) fn ep0(self) -> endpoint::Default { + self.ep0 + } + + async fn get_raw_descriptors(&mut self) -> BoxWrapper<[u8]> { + self.ep0.get_raw_configuration_descriptors().await + } +} + +struct RawDescriptorParser { + raw: BoxWrapper<[u8]>, + current: usize, + len: usize, +} +impl RawDescriptorParser { + fn new(raw: BoxWrapper<[u8]>) -> Self { + let len = raw.len(); + + Self { + raw, + current: 0, + len, + } + } + + fn parse(&mut self) -> Vec { + let mut v = Vec::new(); + while self.current < self.len && self.raw[self.current] > 0 { + match self.parse_first_descriptor() { + Ok(t) => v.push(t), + Err(e) => debug!("Unrecognized USB descriptor: {:?}", e), + } + } + v + } + + fn parse_first_descriptor(&mut self) -> Result { + let raw = self.cut_raw_descriptor(); + Descriptor::from_slice(&raw) + } + + fn cut_raw_descriptor(&mut self) -> Vec { + let len: usize = self.raw[self.current].into(); + let v = self.raw[self.current..(self.current + len)].to_vec(); + self.current += len; + v + } +} diff --git a/test/src/port/init/endpoints_initializer.rs b/test/src/port/init/endpoints_initializer.rs new file mode 100644 index 00000000..e1e5373d --- /dev/null +++ b/test/src/port/init/endpoints_initializer.rs @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::{descriptor_fetcher::DescriptorFetcher, fully_operational::FullyOperational}; +use crate::{ + exchanger, + exchanger::transfer, + port::endpoint, + structures::{context::Context, descriptor, descriptor::Descriptor, registers}, +}; +use alloc::{sync::Arc, vec::Vec}; +use bit_field::BitField; +use core::convert::TryInto; +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; +use spinning_top::Spinlock; +use transfer::DoorbellWriter; +use x86_64::PhysAddr; +use xhci::context::{EndpointHandler, EndpointType}; + +pub(super) struct EndpointsInitializer { + cx: Arc>, + descriptors: Vec, + endpoints: Vec, + ep0: endpoint::Default, + port_number: u8, + slot_number: u8, +} +impl EndpointsInitializer { + pub(super) fn new(f: DescriptorFetcher, descriptors: Vec) -> Self { + let cx = f.context(); + let endpoints = descriptors_to_endpoints(&f, &descriptors); + let port_number = f.port_number(); + let slot_number = f.slot_number(); + let ep0 = f.ep0(); + + Self { + cx, + descriptors, + endpoints, + ep0, + port_number, + slot_number, + } + } + + pub(super) async fn init(mut self) -> FullyOperational { + self.init_contexts(); + self.set_context_entries(); + self.configure_endpoint().await; + FullyOperational::new(self) + } + + pub(super) fn descriptors(&self) -> Vec { + self.descriptors.clone() + } + + pub(super) fn endpoints(self) -> (endpoint::Default, Vec) { + (self.ep0, self.endpoints) + } + + fn init_contexts(&mut self) { + for e in &mut self.endpoints { + ContextInitializer::new( + &mut self.cx.lock(), + &e.descriptor(), + e.transfer_ring_addr(), + self.port_number, + ) + .init() + } + } + + fn set_context_entries(&mut self) { + let mut cx = self.cx.lock(); + cx.input.device_mut().slot_mut().set_context_entries(31); + } + + async fn configure_endpoint(&mut self) { + let a = self.cx.lock().input.phys_addr(); + exchanger::command::configure_endpoint(a, self.slot_number).await; + } +} + +struct ContextInitializer<'a> { + cx: &'a mut Context, + ep: &'a descriptor::Endpoint, + transfer_ring_addr: PhysAddr, + port_number: u8, +} +impl<'a> ContextInitializer<'a> { + #[allow(clippy::too_many_arguments)] // TODO + fn new( + cx: &'a mut Context, + ep: &'a descriptor::Endpoint, + transfer_ring_addr: PhysAddr, + port_number: u8, + ) -> Self { + Self { + cx, + ep, + transfer_ring_addr, + port_number, + } + } + + fn init(mut self) { + self.set_aflag(); + self.init_ep_context(); + } + + fn set_aflag(&mut self) { + let dci: usize = self.calculate_dci().into(); + let c = self.cx.input.control_mut(); + + c.set_add_context_flag(0); + c.clear_add_context_flag(1); // See xHCI dev manual 4.6.6. + c.set_add_context_flag(dci); + } + + fn calculate_dci(&self) -> u8 { + let a = self.ep.endpoint_address; + 2 * a.get_bits(0..=3) + a.get_bit(7) as u8 + } + + fn init_ep_context(&mut self) { + self.set_interval(); + + let ep_ty = self.ep.ty(); + self.ep_cx().set_endpoint_type(ep_ty); + + // TODO: This initializes the context only for USB2. Branch if the version of a device is + // USB3. + match ep_ty { + EndpointType::Control => self.init_for_control(), + EndpointType::BulkOut | EndpointType::BulkIn => self.init_for_bulk(), + EndpointType::IsochOut + | EndpointType::IsochIn + | EndpointType::InterruptOut + | EndpointType::InterruptIn => self.init_for_isoch_or_interrupt(), + EndpointType::NotValid => unreachable!("Not Valid Endpoint should not exist."), + } + } + + fn init_for_control(&mut self) { + assert_eq!( + self.ep.ty(), + EndpointType::Control, + "Not the Control Endpoint." + ); + + let sz = self.ep.max_packet_size; + let a = self.transfer_ring_addr; + let c = self.ep_cx(); + + c.set_max_packet_size(sz); + c.set_error_count(3); + c.set_tr_dequeue_pointer(a.as_u64()); + c.set_dequeue_cycle_state(); + } + + fn init_for_bulk(&mut self) { + assert!(self.is_bulk(), "Not the Bulk Endpoint."); + + let sz = self.ep.max_packet_size; + let a = self.transfer_ring_addr; + let c = self.ep_cx(); + + c.set_max_packet_size(sz); + c.set_max_burst_size(0); + c.set_error_count(3); + c.set_max_primary_streams(0); + c.set_tr_dequeue_pointer(a.as_u64()); + c.set_dequeue_cycle_state(); + } + + fn is_bulk(&self) -> bool { + let t = self.ep.ty(); + + [EndpointType::BulkOut, EndpointType::BulkIn].contains(&t) + } + + fn init_for_isoch_or_interrupt(&mut self) { + let t = self.ep.ty(); + assert!( + self.is_isoch_or_interrupt(), + "Not the Isochronous or the Interrupt Endpoint." + ); + + let sz = self.ep.max_packet_size; + let a = self.transfer_ring_addr; + let c = self.ep_cx(); + + c.set_max_packet_size(sz & 0x7ff); + c.set_max_burst_size(((sz & 0x1800) >> 11).try_into().unwrap()); + c.set_mult(0); + + if let EndpointType::IsochOut | EndpointType::IsochIn = t { + c.set_error_count(0); + } else { + c.set_error_count(3); + } + c.set_tr_dequeue_pointer(a.as_u64()); + c.set_dequeue_cycle_state(); + } + + fn is_isoch_or_interrupt(&self) -> bool { + let t = self.ep.ty(); + [ + EndpointType::IsochOut, + EndpointType::IsochIn, + EndpointType::InterruptOut, + EndpointType::InterruptIn, + ] + .contains(&t) + } + + // TODO: Is this calculation correct? + fn set_interval(&mut self) { + let s = self.port_speed(); + let t = self.ep.ty(); + let i = self.ep.interval; + + let i = if let PortSpeed::FullSpeed | PortSpeed::LowSpeed = s { + if let EndpointType::IsochOut | EndpointType::IsochIn = t { + i + 2 + } else { + i + 3 + } + } else { + i - 1 + }; + + self.ep_cx().set_interval(i); + } + + fn port_speed(&self) -> PortSpeed { + FromPrimitive::from_u8(registers::handle(|r| { + r.port_register_set + .read_volatile_at((self.port_number - 1).into()) + .portsc + .port_speed() + })) + .expect("Failed to get the Port Speed.") + } + + fn ep_cx(&mut self) -> &mut dyn EndpointHandler { + let ep_i: usize = self.ep.endpoint_address.get_bits(0..=3).into(); + let is_input: usize = self.ep.endpoint_address.get_bit(7) as _; + let dpi = 2 * ep_i + is_input; + + self.cx.input.device_mut().endpoint_mut(dpi) + } +} + +#[derive(Copy, Clone, FromPrimitive)] +enum PortSpeed { + FullSpeed = 1, + LowSpeed = 2, + HighSpeed = 3, + SuperSpeed = 4, + SuperSpeedPlus = 5, +} + +fn descriptors_to_endpoints( + f: &DescriptorFetcher, + descriptors: &[Descriptor], +) -> Vec { + descriptors + .iter() + .filter_map(|desc| { + let _ = &f; + if let Descriptor::Endpoint(e) = desc { + let d = DoorbellWriter::new(f.slot_number(), e.doorbell_value()); + let s = transfer::Sender::new(d); + Some(endpoint::NonDefault::new(*e, s)) + } else { + None + } + }) + .collect() +} diff --git a/test/src/port/init/fully_operational.rs b/test/src/port/init/fully_operational.rs new file mode 100644 index 00000000..2141c496 --- /dev/null +++ b/test/src/port/init/fully_operational.rs @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::endpoints_initializer::EndpointsInitializer; +use crate::{ + port::{ + endpoint, + endpoint::{Error, NonDefault}, + }, + structures::descriptor::Descriptor, + transition_helper::BoxWrapper, +}; +use alloc::vec::Vec; +use core::slice; +use log::debug; +use xhci::context::EndpointType; + +pub(in crate::port) struct FullyOperational { + descriptors: Vec, + def_ep: endpoint::Default, + eps: Vec, +} +impl FullyOperational { + pub(super) fn new(i: EndpointsInitializer) -> Self { + let descriptors = i.descriptors(); + let (def_ep, eps) = i.endpoints(); + + debug!("Endpoints collected"); + + Self { + descriptors, + def_ep, + eps, + } + } + + pub(in super::super) fn ty(&self) -> (u8, u8, u8) { + for d in &self.descriptors { + if let Descriptor::Interface(i) = d { + return i.ty(); + } + } + + unreachable!("HID class must have at least one interface descriptor"); + } + + pub(in super::super) async fn issue_normal_trb( + &mut self, + b: &BoxWrapper, + ty: EndpointType, + ) -> Result<(), Error> { + for ep in &mut self.eps { + if ep.ty() == ty { + ep.issue_normal_trb(b).await; + return Ok(()); + } + } + + Err(Error::NoSuchEndpoint(ty)) + } + + pub(in super::super) async fn set_configure(&mut self, config_val: u8) { + self.def_ep.set_configuration(config_val).await; + } + + pub(in super::super) async fn set_idle(&mut self) { + self.def_ep.set_idle().await; + } + + pub(in super::super) async fn set_boot_protocol(&mut self) { + self.def_ep.set_boot_protocol().await; + } + + pub(in super::super) fn descriptors(&self) -> &[Descriptor] { + &self.descriptors + } +} +impl<'a> IntoIterator for &'a mut FullyOperational { + type Item = &'a mut NonDefault; + type IntoIter = slice::IterMut<'a, NonDefault>; + + fn into_iter(self) -> Self::IntoIter { + self.eps.iter_mut() + } +} diff --git a/test/src/port/init/max_packet_size_setter.rs b/test/src/port/init/max_packet_size_setter.rs new file mode 100644 index 00000000..9980c71f --- /dev/null +++ b/test/src/port/init/max_packet_size_setter.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::{ + descriptor_fetcher::DescriptorFetcher, slot_structures_initializer::SlotStructuresInitializer, +}; +use crate::{exchanger, port::endpoint, structures::context::Context}; +use alloc::sync::Arc; +use spinning_top::Spinlock; + +pub(super) struct MaxPacketSizeSetter { + ep: endpoint::Default, + cx: Arc>, + port_number: u8, + slot_number: u8, +} +impl MaxPacketSizeSetter { + pub(super) fn new(i: SlotStructuresInitializer) -> Self { + let cx = i.context(); + let port_number = i.port_number(); + let slot_number = i.slot_number(); + let ep = i.ep0(); + + Self { + ep, + cx, + port_number, + slot_number, + } + } + + pub(super) async fn set(mut self) -> DescriptorFetcher { + let s = self.max_packet_size().await; + self.set_max_packet_size(s); + self.evaluate_context().await; + + DescriptorFetcher::new(self) + } + + pub(super) fn port_number(&self) -> u8 { + self.port_number + } + + pub(super) fn slot_number(&self) -> u8 { + self.slot_number + } + + pub(super) fn context(&self) -> Arc> { + self.cx.clone() + } + + pub(super) fn ep0(self) -> endpoint::Default { + self.ep + } + + async fn max_packet_size(&mut self) -> u16 { + self.ep.get_max_packet_size().await + } + + fn set_max_packet_size(&mut self, s: u16) { + let mut cx = self.cx.lock(); + let ep_0 = cx.input.device_mut().endpoint_mut(1); + + ep_0.set_max_packet_size(s); + } + + async fn evaluate_context(&self) { + let mut cx = self.cx.lock(); + let i = &mut cx.input; + + i.control_mut().set_add_context_flag(1); + + exchanger::command::evaluate_context(i.phys_addr(), self.slot_number).await + } +} diff --git a/test/src/port/init/mod.rs b/test/src/port/init/mod.rs new file mode 100644 index 00000000..8e151bb2 --- /dev/null +++ b/test/src/port/init/mod.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use fully_operational::FullyOperational; +use resetter::Resetter; + +mod descriptor_fetcher; +mod endpoints_initializer; +pub(super) mod fully_operational; +mod max_packet_size_setter; +mod resetter; +mod slot_structures_initializer; + +pub(super) async fn init(port_number: u8) -> FullyOperational { + let resetter = Resetter::new(port_number); + let slot_structures_initializer = resetter.reset().await; + let max_packet_size_setter = slot_structures_initializer.init().await; + let descriptor_fetcher = max_packet_size_setter.set().await; + let endpoints_initializer = descriptor_fetcher.fetch().await; + endpoints_initializer.init().await +} diff --git a/test/src/port/init/resetter.rs b/test/src/port/init/resetter.rs new file mode 100644 index 00000000..fa8dcd92 --- /dev/null +++ b/test/src/port/init/resetter.rs @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::slot_structures_initializer::SlotStructuresInitializer; +use crate::structures::registers; +use xhci::registers::PortRegisterSet; + +pub(super) struct Resetter { + port_number: u8, +} +impl Resetter { + pub(super) fn new(port_number: u8) -> Self { + Self { port_number } + } + + pub(super) fn port_number(&self) -> u8 { + self.port_number + } + + pub(super) async fn reset(self) -> SlotStructuresInitializer { + self.start_resetting(); + self.wait_until_reset_is_completed(); + SlotStructuresInitializer::new(self).await + } + + fn start_resetting(&self) { + self.update_port_register(|r| { + r.portsc.set_port_reset(); + }); + } + + fn wait_until_reset_is_completed(&self) { + while !self.reset_completed() {} + } + + fn reset_completed(&self) -> bool { + self.read_port_register(|r| r.portsc.port_reset_change()) + } + + fn read_port_register(&self, f: T) -> U + where + T: FnOnce(&PortRegisterSet) -> U, + { + registers::handle(|r| { + f(&r.port_register_set + .read_volatile_at((self.port_number - 1).into())) + }) + } + + fn update_port_register(&self, f: T) + where + T: FnOnce(&mut PortRegisterSet), + { + registers::handle(|r| { + r.port_register_set + .update_volatile_at((self.port_number - 1).into(), f) + }) + } +} diff --git a/test/src/port/init/slot_structures_initializer.rs b/test/src/port/init/slot_structures_initializer.rs new file mode 100644 index 00000000..6d256c34 --- /dev/null +++ b/test/src/port/init/slot_structures_initializer.rs @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::{max_packet_size_setter::MaxPacketSizeSetter, resetter::Resetter}; +use crate::{ + exchanger, + port::endpoint, + structures::{context::Context, dcbaa, registers}, +}; +use alloc::sync::Arc; +use exchanger::{transfer, transfer::DoorbellWriter}; +use spinning_top::Spinlock; +use xhci::context::EndpointType; + +pub(super) struct SlotStructuresInitializer { + port_number: u8, + slot_number: u8, + cx: Arc>, + ep: endpoint::Default, +} +impl SlotStructuresInitializer { + pub(super) async fn new(r: Resetter) -> Self { + let slot_number = exchanger::command::enable_device_slot().await; + let cx = Arc::new(Spinlock::new(Context::default())); + let dbl_writer = DoorbellWriter::new(slot_number, 1); + + Self { + port_number: r.port_number(), + slot_number, + cx, + ep: endpoint::Default::new(transfer::Sender::new(dbl_writer)), + } + } + + pub(super) async fn init(self) -> MaxPacketSizeSetter { + self.init_input_context(); + self.init_endpoint0_context(); + self.register_with_dcbaa(); + self.issue_address_device().await; + + MaxPacketSizeSetter::new(self) + } + + pub(super) fn port_number(&self) -> u8 { + self.port_number + } + + pub(super) fn slot_number(&self) -> u8 { + self.slot_number + } + + pub(super) fn context(&self) -> Arc> { + self.cx.clone() + } + + pub(super) fn ep0(self) -> endpoint::Default { + self.ep + } + + fn init_input_context(&self) { + InputContextInitializer::new(&mut self.cx.lock(), self.port_number).init() + } + + fn init_endpoint0_context(&self) { + Ep0ContextInitializer::new(&mut self.cx.lock(), self.port_number, &self.ep).init() + } + + fn register_with_dcbaa(&self) { + let a = self.cx.lock().output.phys_addr(); + dcbaa::register(self.slot_number.into(), a); + } + + async fn issue_address_device(&self) { + let cx_addr = self.cx.lock().input.phys_addr(); + exchanger::command::address_device(cx_addr, self.slot_number).await; + } +} + +struct InputContextInitializer<'a> { + context: &'a mut Context, + port_number: u8, +} +impl<'a> InputContextInitializer<'a> { + fn new(context: &'a mut Context, port_number: u8) -> Self { + Self { + context, + port_number, + } + } + + fn init(&mut self) { + self.init_input_control(); + self.init_input_slot(); + } + + fn init_input_control(&mut self) { + let input_control = self.context.input.control_mut(); + input_control.set_add_context_flag(0); + input_control.set_add_context_flag(1); + } + + fn init_input_slot(&mut self) { + let slot = self.context.input.device_mut().slot_mut(); + slot.set_context_entries(1); + slot.set_root_hub_port_number(self.port_number); + } +} + +struct Ep0ContextInitializer<'a> { + cx: &'a mut Context, + port_number: u8, + ep: &'a endpoint::Default, +} +impl<'a> Ep0ContextInitializer<'a> { + fn new(cx: &'a mut Context, port_number: u8, ep: &'a endpoint::Default) -> Self { + Self { + cx, + port_number, + ep, + } + } + + fn init(self) { + let s = self.get_max_packet_size(); + let ep_0 = self.cx.input.device_mut().endpoint_mut(1); + + ep_0.set_endpoint_type(EndpointType::Control); + ep_0.set_max_packet_size(s); + ep_0.set_tr_dequeue_pointer(self.ep.ring_addr().as_u64()); + ep_0.set_dequeue_cycle_state(); + ep_0.set_error_count(3); + } + + // TODO: This function does not check the actual port speed, instead it uses the normal + // correspondence between PSI and the port speed. + // The actual port speed is listed on the xHCI supported protocol capability. + // Check the capability and fetch the actual port speed. Then return the max packet size. + fn get_max_packet_size(&self) -> u16 { + let psi = registers::handle(|r| { + r.port_register_set + .read_volatile_at((self.port_number - 1).into()) + .portsc + .port_speed() + }); + + match psi { + 1 | 3 => 64, + 2 => 8, + 4 => 512, + _ => unimplemented!("PSI: {}", psi), + } + } +} diff --git a/test/src/port/mod.rs b/test/src/port/mod.rs new file mode 100644 index 00000000..d771da1c --- /dev/null +++ b/test/src/port/mod.rs @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::structures::registers; +use crate::multitask::{self, task::Task}; +use alloc::collections::VecDeque; +use conquer_once::spin::Lazy; +use core::{future::Future, pin::Pin, task::Poll}; +use futures_util::task::AtomicWaker; +use init::fully_operational::FullyOperational; +use log::{info, warn}; +use spinning_top::Spinlock; + +mod class_driver; +mod endpoint; +mod init; +mod spawner; + +static CURRENT_RESET_PORT: Lazy> = + Lazy::new(|| Spinlock::new(ResetPort::new())); + +struct ResetPort { + resetting: bool, + wakers: VecDeque, +} +impl ResetPort { + fn new() -> Self { + Self { + resetting: false, + wakers: VecDeque::new(), + } + } + + fn complete_reset(&mut self) { + self.resetting = false; + if let Some(w) = self.wakers.pop_front() { + w.wake(); + } + } + + fn resettable(&mut self, waker: AtomicWaker) -> bool { + if self.resetting { + self.wakers.push_back(waker); + false + } else { + self.resetting = true; + true + } + } +} + +pub(crate) fn try_spawn(port_idx: u8) -> Result<(), spawner::PortNotConnected> { + spawner::try_spawn(port_idx) +} + +async fn main(port_number: u8) { + let fully_operational = init_port_and_slot_exclusively(port_number).await; + + match fully_operational.ty() { + (3, 1, 2) => { + multitask::add(Task::new_poll(class_driver::mouse::task(fully_operational))); + } + (3, 1, 1) => { + multitask::add(Task::new_poll(class_driver::keyboard::task( + fully_operational, + ))); + } + (8, _, _) => multitask::add(Task::new(class_driver::mass_storage::task( + fully_operational, + ))), + t => warn!("Unknown device: {:?}", t), + } +} + +async fn init_port_and_slot_exclusively(port_number: u8) -> FullyOperational { + let reset_waiter = ResetWaiterFuture; + reset_waiter.await; + + let fully_operational = init::init(port_number).await; + CURRENT_RESET_PORT.lock().complete_reset(); + info!("Port {} reset completed.", port_number); + fully_operational +} + +pub(crate) fn spawn_all_connected_port_tasks() { + spawner::spawn_all_connected_ports(); +} + +fn max_num() -> u8 { + registers::handle(|r| r.capability.hcsparams1.read_volatile().number_of_ports()) +} + +fn connected(port_number: u8) -> bool { + registers::handle(|r| { + r.port_register_set + .read_volatile_at((port_number - 1).into()) + .portsc + .current_connect_status() + }) +} + +struct ResetWaiterFuture; +impl Future for ResetWaiterFuture { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> Poll { + let waker = AtomicWaker::new(); + waker.register(cx.waker()); + if CURRENT_RESET_PORT.lock().resettable(waker) { + Poll::Ready(()) + } else { + Poll::Pending + } + } +} diff --git a/test/src/port/spawner.rs b/test/src/port/spawner.rs new file mode 100644 index 00000000..ae320553 --- /dev/null +++ b/test/src/port/spawner.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::multitask; +use alloc::{vec, vec::Vec}; +use conquer_once::spin::Lazy; +use multitask::task::Task; +use spinning_top::Spinlock; + +static SPAWN_STATUS: Lazy>> = + Lazy::new(|| Spinlock::new(vec![false; super::max_num().into()])); + +pub(crate) fn spawn_all_connected_ports() { + let n = super::max_num(); + for i in 0..n { + let _ = try_spawn(i + 1); + } +} + +pub(crate) fn try_spawn(port_number: u8) -> Result<(), PortNotConnected> { + if spawnable(port_number) { + spawn(port_number); + Ok(()) + } else { + Err(PortNotConnected) + } +} + +fn spawn(p: u8) { + mark_as_spawned(p); + add_task_for_port(p); +} + +fn add_task_for_port(p: u8) { + multitask::add(Task::new(super::main(p))); +} + +fn spawnable(p: u8) -> bool { + super::connected(p) && !spawned(p) +} + +fn spawned(p: u8) -> bool { + SPAWN_STATUS.lock()[usize::from(p)] +} + +fn mark_as_spawned(p: u8) { + SPAWN_STATUS.lock()[usize::from(p)] = true; +} + +#[derive(Debug)] +pub(crate) struct PortNotConnected; diff --git a/test/src/ports/context.rs b/test/src/ports/context.rs deleted file mode 100644 index a37a2e3d..00000000 --- a/test/src/ports/context.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::registers; - -use { - alloc::boxed::Box, - xhci::context::{ - Device32Byte, Device64Byte, DeviceHandler, Input32Byte, Input64Byte, InputControlHandler, - InputHandler, - }, -}; - -pub struct Context { - pub input: Input, - pub output: Box, -} -impl Context { - pub fn new() -> Self { - Self { - input: Input::new(), - output: Device::new().into(), - } - } -} - -pub(crate) enum Input { - Byte64(Box), - Byte32(Box), -} -impl Input { - pub fn control_mut(&mut self) -> &mut dyn InputControlHandler { - match self { - Self::Byte32(b32) => b32.control_mut(), - Self::Byte64(b64) => b64.control_mut(), - } - } - - pub fn device_mut(&mut self) -> &mut dyn DeviceHandler { - match self { - Self::Byte32(b32) => b32.device_mut(), - Self::Byte64(b64) => b64.device_mut(), - } - } - - pub fn phys_addr(&self) -> u64 { - match self { - Self::Byte32(b32) => b32.as_ref() as *const _ as u64, - Self::Byte64(b64) => b64.as_ref() as *const _ as u64, - } - } - - fn new() -> Self { - if csz() { - Self::Byte64(Input64Byte::default().into()) - } else { - Self::Byte32(Input32Byte::default().into()) - } - } -} - -pub enum Device { - Byte64(Box), - Byte32(Box), -} -impl Device { - fn new() -> Self { - if csz() { - Self::Byte64(Device64Byte::default().into()) - } else { - Self::Byte32(Device32Byte::default().into()) - } - } -} - -fn csz() -> bool { - registers::handle(|r| r.capability.hccparams1.read_volatile().context_size()) -} diff --git a/test/src/ports/endpoint.rs b/test/src/ports/endpoint.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/test/src/ports/mod.rs b/test/src/ports/mod.rs deleted file mode 100644 index bbcb2aaa..00000000 --- a/test/src/ports/mod.rs +++ /dev/null @@ -1,277 +0,0 @@ -mod context; - -use self::context::Context; -use crate::dcbaa; -use crate::{command_ring, registers, transfer_ring::TransferRingController}; -use alloc::vec::Vec; -use core::ops::DerefMut; -use spinning_top::Spinlock; -use xhci::ring::trb::event::PortStatusChange; -use xhci::{context::EndpointType, registers::PortRegisterSet}; - -static ENABLING_SLOTS: Spinlock> = Spinlock::new(Vec::new()); -static PORTS_AND_SLOTS: Spinlock> = Spinlock::new(Vec::new()); -static CONTEXTS: Spinlock> = Spinlock::new(Vec::new()); - -pub fn init_all_ports() { - let num_ports = num_ports(); - - for port in 0..num_ports { - if connected(port) { - reset_port(port); - command_ring::send_enable_slot(); - - lock_enabling_slots().push(port); - } - } -} - -pub fn process_trb(trb: &PortStatusChange) { - PortRegisterHandler::new(trb.port_id()).update(|r| { - if r.portsc.current_connect_status() { - todo!() - } - }); -} - -pub fn init_structures(slot: u8) { - let port = lock_enabling_slots().pop().expect("No enabling slots"); - - PORTS_AND_SLOTS - .try_lock() - .expect("Ports and slots is already locked") - .push((port, slot)); - - init_structures_for_port(port, slot); -} - -pub fn init_structures_for_port(port: u8, slot: u8) { - let mut cx = Context::new(); - - StructureInitializer::new(port, slot, cx).create(); -} - -pub fn set_max_packet_size(slot: u8) { - let port = PORTS_AND_SLOTS - .try_lock() - .expect("Ports and slots is already locked") - .iter() - .find(|(_, s)| *s == slot) - .expect("No port for the slot") - .0; -} - -fn lock_enabling_slots() -> impl DerefMut> { - ENABLING_SLOTS - .try_lock() - .expect("Enabling slots is already locked") -} - -fn connected(port: u8) -> bool { - registers::handle(|r| { - r.port_register_set - .read_volatile_at(port.into()) - .portsc - .current_connect_status() - }) -} - -fn reset_port(port: u8) { - Resetter::new(port).reset(); -} - -fn num_ports() -> u8 { - registers::handle(|r| r.capability.hcsparams1.read_volatile().number_of_ports()) -} - -struct Resetter { - regs: PortRegisterHandler, -} -impl Resetter { - fn new(port_number: u8) -> Self { - Self { - regs: PortRegisterHandler::new(port_number), - } - } - - fn reset(mut self) { - self.start_resetting(); - self.wait_utnil_reset_completed(); - } - - fn start_resetting(&mut self) { - self.regs.update(|r| { - r.portsc.set_port_reset(); - }); - } - - fn wait_utnil_reset_completed(&self) { - while !self.reset_completed() {} - } - - fn reset_completed(&self) -> bool { - self.regs.read().portsc.port_reset_change() - } -} - -struct SlotEnabler {} -impl SlotEnabler { - fn new() -> Self { - Self {} - } - - fn enable(&mut self) { - command_ring::send_enable_slot(); - } -} - -struct StructureInitializer { - port: u8, - slot: u8, - ring: TransferRingController, - cx: Context, -} -impl StructureInitializer { - fn new(port: u8, slot: u8, cx: Context) -> Self { - Self { - port, - slot, - ring: TransferRingController::new(), - cx, - } - } - - fn create(mut self) { - self.init_input_context(); - self.init_ep0_context(); - self.register_with_dcbaa(); - self.issue_address_device_command(); - - CONTEXTS - .try_lock() - .expect("Contexts is already locked") - .push(self.cx); - } - - fn init_input_context(&mut self) { - InputContextInitializer::new(&mut self.cx, self.port).init(); - } - - fn init_ep0_context(&mut self) { - Ep0ContextInitializer::new( - &mut self.cx, - self.port, - &self.ring, - PortRegisterHandler::new(self.port), - ) - .init(); - } - - fn register_with_dcbaa(&mut self) { - dcbaa::register_address(self.port, self.cx.input.phys_addr()); - } - - fn issue_address_device_command(&mut self) { - command_ring::send_address_device(self.cx.input.phys_addr(), self.slot); - } -} - -struct InputContextInitializer<'a> { - cx: &'a mut Context, - port: u8, -} -impl<'a> InputContextInitializer<'a> { - fn new(cx: &'a mut Context, port: u8) -> Self { - Self { cx, port } - } - - fn init(&mut self) { - self.init_input_control(); - self.init_input_slot(); - } - - fn init_input_control(&mut self) { - let c = self.cx.input.control_mut(); - - c.set_add_context_flag(0); - c.set_add_context_flag(1); - } - - fn init_input_slot(&mut self) { - let s = self.cx.input.device_mut().slot_mut(); - - s.set_context_entries(1); - - // Port ID starts from 1. - s.set_root_hub_port_number(self.port + 1); - } -} - -struct Ep0ContextInitializer<'a> { - cx: &'a mut Context, - port: u8, - ring: &'a TransferRingController, - regs: PortRegisterHandler, -} -impl<'a> Ep0ContextInitializer<'a> { - fn new( - cx: &'a mut Context, - port: u8, - ring: &'a TransferRingController, - regs: PortRegisterHandler, - ) -> Self { - Self { - cx, - port, - ring, - regs, - } - } - - fn init(self) { - let s = self.get_max_packet_size(); - let ep_0 = self.cx.input.device_mut().endpoint_mut(1); - - ep_0.set_endpoint_type(EndpointType::Control); - ep_0.set_max_packet_size(s); - ep_0.set_tr_dequeue_pointer(self.ring.head_addr()); - ep_0.set_dequeue_cycle_state(); - ep_0.set_error_count(3); - } - - // TODO: Read the actual speed from xHCI supported protocol capability. - fn get_max_packet_size(&self) -> u16 { - match self.regs.read().portsc.port_speed() { - 1 | 3 => 64, - 2 => 8, - 4 => 512, - x => todo!("PSI: {}", x), - } - } -} - -struct PortRegisterHandler { - port_number: u8, -} -impl PortRegisterHandler { - fn new(port_number: u8) -> Self { - Self { port_number } - } - - fn read(&self) -> PortRegisterSet { - registers::handle(|r| { - r.port_register_set - .read_volatile_at(self.port_number.into()) - }) - } - - fn update(&mut self, f: T) - where - T: FnOnce(&mut PortRegisterSet), - { - registers::handle(|r| { - r.port_register_set - .update_volatile_at(self.port_number.into(), f) - }) - } -} diff --git a/test/src/registers.rs b/test/src/registers.rs deleted file mode 100644 index 2b656abf..00000000 --- a/test/src/registers.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::mapper::Mapper; -use bit_field::BitField; -use conquer_once::spin::OnceCell; -use spinning_top::Spinlock; -use xhci::Registers; - -static REGISTERS: OnceCell>> = OnceCell::uninit(); - -pub fn init() { - let xhc_config_space = crate::pci::iter_xhc().next().expect("xHC not found"); - - // See [1] for the structure of base address registers. - // - // [1]: https://wiki.osdev.org/PCI#Base_Address_Registers - let mmio_low = xhc_config_space.base_address_register(0); - let mmio_high = xhc_config_space.base_address_register(1); - - let bar_type = mmio_low.get_bits(1..=2); - - assert_eq!( - bar_type, 2, - "The MMIO of xHC must be mapped to memory and 64-bit wide." - ); - - let mmio_base = (((mmio_high as u64) << 32) | (mmio_low as u64 & 0xffff_fff0)) as usize; - - REGISTERS.init_once(|| - // SAFETY: The function will be called only once. - unsafe { Spinlock::new(xhci::Registers::new(mmio_base, Mapper) )}); -} - -// This function receives a closure instead of returning a lock guard to reduce -// the possibility of deadlocks. -pub fn handle(f: impl FnOnce(&mut Registers) -> T) -> T { - let mut regs = REGISTERS - .try_get() - .expect("xHC not initialized") - .try_lock() - .expect("xHC is already locked"); - - f(&mut regs) -} diff --git a/test/src/scratchpat.rs b/test/src/scratchpat.rs deleted file mode 100644 index fb0ca3c2..00000000 --- a/test/src/scratchpat.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::registers; - -pub fn init() { - let num_of_buffers = registers::handle(|r| { - r.capability - .hcsparams2 - .read_volatile() - .max_scratchpad_buffers() - }); - - if num_of_buffers > 0 { - todo!("Implement scratchpad buffer initialization"); - } -} diff --git a/test/src/structures/context.rs b/test/src/structures/context.rs new file mode 100644 index 00000000..0597d0a4 --- /dev/null +++ b/test/src/structures/context.rs @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::transition_helper::BoxWrapper; + +use super::registers; +use alloc::boxed::Box; +use x86_64::PhysAddr; +use xhci::context::{ + Device32Byte, Device64Byte, DeviceHandler, Input32Byte, Input64Byte, InputControlHandler, + InputHandler, +}; + +pub(crate) struct Context { + pub(crate) input: Input, + pub(crate) output: BoxWrapper, +} +impl Default for Context { + fn default() -> Self { + Self { + input: Input::default(), + output: Device::default().into(), + } + } +} + +pub(crate) enum Input { + Byte64(BoxWrapper), + Byte32(BoxWrapper), +} +impl Input { + pub(crate) fn control_mut(&mut self) -> &mut dyn InputControlHandler { + match self { + Self::Byte32(b32) => b32.control_mut(), + Self::Byte64(b64) => b64.control_mut(), + } + } + + pub(crate) fn device_mut(&mut self) -> &mut dyn DeviceHandler { + match self { + Self::Byte32(b32) => b32.device_mut(), + Self::Byte64(b64) => b64.device_mut(), + } + } + + pub(crate) fn phys_addr(&self) -> PhysAddr { + match self { + Self::Byte32(b32) => b32.phys_addr(), + Self::Byte64(b64) => b64.phys_addr(), + } + } +} +impl Default for Input { + fn default() -> Self { + if csz() { + Self::Byte64(Input64Byte::default().into()) + } else { + Self::Byte32(Input32Byte::default().into()) + } + } +} + +pub(crate) enum Device { + Byte64(Box), + Byte32(Box), +} +impl Default for Device { + fn default() -> Self { + if csz() { + Self::Byte64(Device64Byte::default().into()) + } else { + Self::Byte32(Device32Byte::default().into()) + } + } +} + +fn csz() -> bool { + registers::handle(|r| r.capability.hccparams1.read_volatile().context_size()) +} diff --git a/test/src/structures/dcbaa.rs b/test/src/structures/dcbaa.rs new file mode 100644 index 00000000..0713645d --- /dev/null +++ b/test/src/structures/dcbaa.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::transition_helper::BoxWrapper; + +use super::registers; +use conquer_once::spin::Lazy; +use core::ops::{Index, IndexMut}; +use spinning_top::Spinlock; +use x86_64::PhysAddr; + +static DCBAA: Lazy> = + Lazy::new(|| Spinlock::new(DeviceContextBaseAddressArray::new())); + +pub(crate) fn init() { + DCBAA.lock().init(); +} + +pub(crate) fn register(port_id: usize, a: PhysAddr) { + DCBAA.lock()[port_id] = a; +} + +pub(crate) struct DeviceContextBaseAddressArray { + arr: BoxWrapper<[PhysAddr]>, +} +impl DeviceContextBaseAddressArray { + fn new() -> Self { + let arr = BoxWrapper::new_slice(PhysAddr::zero(), Self::num_of_slots()); + Self { arr } + } + + fn init(&self) { + self.register_address_to_xhci_register(); + } + + fn num_of_slots() -> usize { + registers::handle(|r| { + r.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() + + 1 + }) + .into() + } + + fn register_address_to_xhci_register(&self) { + registers::handle(|r| { + let _ = &self; + r.operational.dcbaap.update_volatile(|d| { + let _ = &self; + d.set(self.phys_addr().as_u64()); + }) + }) + } + + fn phys_addr(&self) -> PhysAddr { + self.arr.phys_addr() + } +} +impl Index for DeviceContextBaseAddressArray { + type Output = PhysAddr; + fn index(&self, index: usize) -> &Self::Output { + &self.arr[index] + } +} +impl IndexMut for DeviceContextBaseAddressArray { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.arr[index] + } +} diff --git a/test/src/structures/descriptor.rs b/test/src/structures/descriptor.rs new file mode 100644 index 00000000..d9abbe92 --- /dev/null +++ b/test/src/structures/descriptor.rs @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use bit_field::BitField; +use core::{convert::TryInto, ptr}; +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; +use xhci::context::EndpointType; + +#[derive(Copy, Clone, Debug)] +pub(crate) enum Descriptor { + Device(Device), + Configuration(Configuration), + Str, + Interface(Interface), + Endpoint(Endpoint), + Hid, +} +impl Descriptor { + pub(crate) fn from_slice(raw: &[u8]) -> Result { + assert_eq!(raw.len(), raw[0].into()); + match FromPrimitive::from_u8(raw[1]) { + Some(t) => { + let raw: *const [u8] = raw; + match t { + // SAFETY: This operation is safe because the length of `raw` is equivalent to the + // one of the descriptor. + Ty::Device => Ok(Self::Device(unsafe { ptr::read(raw.cast()) })), + Ty::Configuration => Ok(Self::Configuration(unsafe { ptr::read(raw.cast()) })), + Ty::Str => Ok(Self::Str), + Ty::Interface => Ok(Self::Interface(unsafe { ptr::read(raw.cast()) })), + Ty::Endpoint => Ok(Self::Endpoint(unsafe { ptr::read(raw.cast()) })), + Ty::Hid => Ok(Self::Hid), + } + } + None => Err(Error::UnrecognizedType(raw[1])), + } + } +} + +#[derive(Copy, Clone, Default, Debug)] +#[repr(C, packed)] +pub(crate) struct Device { + len: u8, + descriptor_type: u8, + cd_usb: u16, + class: u8, + subclass: u8, + protocol: u8, + max_packet_size0: u8, + vendor: u16, + product_id: u16, + device: u16, + manufacture: u8, + product: u8, + serial_number: u8, + num_configurations: u8, +} +impl Device { + pub(crate) fn max_packet_size(&self) -> u16 { + if let (3, _) = self.version() { + 2_u16.pow(self.max_packet_size0.into()) + } else { + self.max_packet_size0.into() + } + } + + fn version(&self) -> (u8, u8) { + let cd_usb = self.cd_usb; + + ( + (cd_usb >> 8).try_into().unwrap(), + (cd_usb & 0xff).try_into().unwrap(), + ) + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C, packed)] +pub(crate) struct Configuration { + length: u8, + ty: u8, + total_length: u16, + num_interfaces: u8, + config_val: u8, + config_string: u8, + attributes: u8, + max_power: u8, +} +impl Configuration { + pub(crate) fn config_val(&self) -> u8 { + self.config_val + } +} + +#[derive(Copy, Clone, Default, Debug)] +#[repr(C, packed)] +pub(crate) struct Interface { + len: u8, + descriptor_type: u8, + interface_number: u8, + alternate_setting: u8, + num_endpoints: u8, + interface_class: u8, + interface_subclass: u8, + interface_protocol: u8, + interface: u8, +} +impl Interface { + pub(crate) fn ty(&self) -> (u8, u8, u8) { + ( + self.interface_class, + self.interface_subclass, + self.interface_protocol, + ) + } +} + +#[derive(Copy, Clone, Default, Debug)] +#[repr(C, packed)] +pub(crate) struct Endpoint { + len: u8, + descriptor_type: u8, + pub(crate) endpoint_address: u8, + pub(crate) attributes: u8, + pub(crate) max_packet_size: u16, + pub(crate) interval: u8, +} +impl Endpoint { + pub(crate) fn ty(self) -> EndpointType { + EndpointType::from_u8(if self.attributes == 0 { + 4 + } else { + self.attributes.get_bits(0..=1) + + if self.endpoint_address.get_bit(7) { + 4 + } else { + 0 + } + }) + .expect("EndpointType must be convertible from `attributes` and `endpoint_address`.") + } + + pub(crate) fn doorbell_value(self) -> u32 { + 2 * u32::from(self.endpoint_address.get_bits(0..=3)) + + self.endpoint_address.get_bit(7) as u32 + } +} + +#[derive(FromPrimitive)] +pub(crate) enum Ty { + Device = 1, + Configuration = 2, + Str = 3, + Interface = 4, + Endpoint = 5, + Hid = 33, +} + +#[derive(Debug)] +pub(crate) enum Error { + UnrecognizedType(u8), +} diff --git a/test/src/structures/extended_capabilities.rs b/test/src/structures/extended_capabilities.rs new file mode 100644 index 00000000..5bbcb368 --- /dev/null +++ b/test/src/structures/extended_capabilities.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::registers; +use crate::mapper::Mapper; +use conquer_once::spin::OnceCell; +use core::convert::TryInto; +use spinning_top::Spinlock; +use x86_64::PhysAddr; +use xhci::{extended_capabilities, ExtendedCapability}; + +static EXTENDED_CAPABILITIES: OnceCell>>> = + OnceCell::uninit(); + +pub(crate) unsafe fn init(mmio_base: PhysAddr) { + let hccparams1 = registers::handle(|r| r.capability.hccparams1.read_volatile()); + + EXTENDED_CAPABILITIES + .try_init_once(|| { + Spinlock::new(extended_capabilities::List::new( + mmio_base.as_u64().try_into().unwrap(), + hccparams1, + Mapper, + )) + }) + .expect("Failed to initialize `EXTENDED_CAPABILITIES`."); +} + +pub(crate) fn iter() -> Option< + impl Iterator, extended_capabilities::NotSupportedId>>, +> { + Some( + EXTENDED_CAPABILITIES + .try_get() + .expect("`EXTENDED_CAPABILITIES` is not initialized.`") + .lock() + .as_mut()? + .into_iter(), + ) +} diff --git a/test/src/structures/mod.rs b/test/src/structures/mod.rs new file mode 100644 index 00000000..e2538cba --- /dev/null +++ b/test/src/structures/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub(crate) mod context; +pub(crate) mod dcbaa; +pub(crate) mod descriptor; +pub(super) mod extended_capabilities; +pub(super) mod registers; +pub(crate) mod ring; +pub(crate) mod scratchpad; diff --git a/test/src/structures/registers.rs b/test/src/structures/registers.rs new file mode 100644 index 00000000..a44655c5 --- /dev/null +++ b/test/src/structures/registers.rs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::mapper::Mapper; +use conquer_once::spin::OnceCell; +use core::convert::TryInto; +use spinning_top::Spinlock; +use x86_64::PhysAddr; +use xhci::Registers; + +static REGISTERS: OnceCell>> = OnceCell::uninit(); + +pub(crate) unsafe fn init(mmio_base: PhysAddr) { + let mmio_base: usize = mmio_base.as_u64().try_into().unwrap(); + + REGISTERS + .try_init_once(|| Spinlock::new(Registers::new(mmio_base, Mapper))) + .expect("Failed to initialize `REGISTERS`.") +} + +/// Handle xHCI registers. +/// +/// To avoid deadlocking, this method takes a closure. Caller is supposed not to call this method +/// inside the closure, otherwise a deadlock will happen. +/// +/// Alternative implementation is to define a method which returns `impl Deref`, but this will expand the scope of the mutex guard, increasing the possibility of +/// deadlocks. +pub(crate) fn handle(f: T) -> U +where + T: FnOnce(&mut Registers) -> U, +{ + let mut r = REGISTERS.try_get().unwrap().lock(); + f(&mut r) +} diff --git a/test/src/structures/ring/command/mod.rs b/test/src/structures/ring/command/mod.rs new file mode 100644 index 00000000..8f87f587 --- /dev/null +++ b/test/src/structures/ring/command/mod.rs @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::CycleBit; +use crate::{registers, transition_helper::BoxWrapper}; +use trb::Link; +use x86_64::{ + structures::paging::{PageSize, Size4KiB}, + PhysAddr, +}; +use xhci::ring::{trb, trb::command}; + +#[allow(clippy::cast_possible_truncation)] +const NUM_OF_TRBS: usize = Size4KiB::SIZE as usize / trb::BYTES; + +pub(crate) struct Ring { + raw: Raw, +} +impl Ring { + pub(crate) fn new() -> Self { + Self { raw: Raw::new() } + } + + pub(crate) fn init(&mut self) { + Initializer::new(self).init(); + } + + pub(crate) fn enqueue(&mut self, trb: command::Allowed) -> PhysAddr { + let a = self.raw.enqueue(trb); + Self::notify_command_is_sent(); + a + } + + fn phys_addr(&self) -> PhysAddr { + self.raw.head_addr() + } + + fn notify_command_is_sent() { + registers::handle(|r| { + r.doorbell.update_volatile_at(0, |r| { + r.set_doorbell_target(0); + }); + }) + } +} +impl Default for Ring { + fn default() -> Self { + Self::new() + } +} + +struct Raw { + raw: BoxWrapper<[[u32; 4]]>, + enq_p: usize, + c: CycleBit, +} +impl Raw { + fn new() -> Self { + Self { + raw: BoxWrapper::new_slice([0; 4], NUM_OF_TRBS), + enq_p: 0, + c: CycleBit::new(true), + } + } + + fn enqueue(&mut self, mut trb: command::Allowed) -> PhysAddr { + self.set_cycle_bit(&mut trb); + self.write_trb(trb); + let trb_a = self.enq_addr(); + self.increment(); + trb_a + } + + fn write_trb(&mut self, trb: command::Allowed) { + // TODO: Write four 32-bit values. This way of writing is described in the spec, although + // I cannot find which section has the description. + self.raw[self.enq_p] = trb.into_raw(); + } + + fn increment(&mut self) { + self.enq_p += 1; + if !self.enq_p_within_ring() { + self.enq_link(); + self.move_enq_p_to_the_beginning(); + } + } + + fn enq_p_within_ring(&self) -> bool { + self.enq_p < self.len() - 1 + } + + fn enq_link(&mut self) { + // Don't call `enqueue`. It will return an `Err` value as there is no space for link TRB. + let t = *Link::default().set_ring_segment_pointer(self.head_addr().as_u64()); + let mut t = command::Allowed::Link(t); + self.set_cycle_bit(&mut t); + self.raw[self.enq_p] = t.into_raw(); + } + + fn move_enq_p_to_the_beginning(&mut self) { + self.enq_p = 0; + self.c.toggle(); + } + + fn enq_addr(&self) -> PhysAddr { + self.head_addr() + trb::BYTES * self.enq_p + } + + fn head_addr(&self) -> PhysAddr { + self.raw.phys_addr() + } + + fn len(&self) -> usize { + self.raw.len() + } + + fn set_cycle_bit(&self, trb: &mut command::Allowed) { + if self.c == CycleBit::new(true) { + trb.set_cycle_bit(); + } else { + trb.clear_cycle_bit(); + } + } +} + +struct Initializer<'a> { + ring: &'a Ring, +} +impl<'a> Initializer<'a> { + fn new(ring: &'a Ring) -> Self { + Self { ring } + } + + fn init(&mut self) { + registers::handle(|r| { + let a = self.ring.phys_addr(); + + // Do not split this closure to avoid read-modify-write bug. Reading fields may return + // 0, this will cause writing 0 to fields. + r.operational.crcr.update_volatile(|c| { + c.set_command_ring_pointer(a.as_u64()); + c.set_ring_cycle_state(); + }); + }) + } +} diff --git a/test/src/structures/ring/event/mod.rs b/test/src/structures/ring/event/mod.rs new file mode 100644 index 00000000..41a43648 --- /dev/null +++ b/test/src/structures/ring/event/mod.rs @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::CycleBit; +use crate::{exchanger::receiver, port, structures::registers, transition_helper::BoxWrapper}; +use alloc::vec::Vec; +use bit_field::BitField; +use core::{ + convert::TryInto, + pin::Pin, + task::{Context, Poll}, +}; +use futures_util::{stream::Stream, StreamExt}; +use log::{debug, info, warn}; +use segment_table::SegmentTable; +use x86_64::{ + structures::paging::{PageSize, Size4KiB}, + PhysAddr, +}; +use xhci::ring::{trb, trb::event}; + +mod segment_table; + +pub(crate) async fn task(mut ring: Ring) { + debug!("This is the Event ring task."); + while let Some(trb) = ring.next().await { + info!("TRB: {:?}", trb); + if let event::Allowed::CommandCompletion(_) = trb { + receiver::receive(trb); + } else if let event::Allowed::TransferEvent(_) = trb { + receiver::receive(trb); + } else if let event::Allowed::PortStatusChange(p) = trb { + let _ = port::try_spawn(p.port_id()); + } + } +} + +#[allow(clippy::cast_possible_truncation)] +const MAX_NUM_OF_TRB_IN_QUEUE: u16 = Size4KiB::SIZE as u16 / trb::BYTES as u16; + +pub(crate) struct Ring { + segment_table: SegmentTable, + raw: Raw, +} +impl Ring { + pub(crate) fn new() -> Self { + let max_num_of_erst = registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .event_ring_segment_table_max() + }); + + Self { + segment_table: SegmentTable::new(max_num_of_erst.into()), + raw: Raw::new(), + } + } + + pub(crate) fn init(&mut self) { + self.init_dequeue_ptr(); + self.init_tbl(); + } + + fn init_dequeue_ptr(&mut self) { + self.raw.update_deq_p_with_xhci() + } + + fn phys_addr_to_segment_table(&self) -> PhysAddr { + self.segment_table.phys_addr() + } + + fn init_tbl(&mut self) { + SegTblInitializer::new(self).init(); + } + + fn try_dequeue(&mut self) -> Option { + self.raw.try_dequeue() + } + + fn ring_addrs(&self) -> Vec { + self.raw.head_addrs() + } + + fn iter_tbl_entries_mut(&mut self) -> impl Iterator { + self.segment_table.iter_mut() + } +} +impl Stream for Ring { + type Item = event::Allowed; + + fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Pin::into_inner(self) + .try_dequeue() + .map_or_else(|| Poll::Pending, |trb| Poll::Ready(Some(trb))) + } +} + +struct Raw { + rings: Vec>, + c: CycleBit, + deq_p_seg: usize, + deq_p_trb: usize, +} +impl Raw { + fn new() -> Self { + let rings = Self::new_rings(); + Self { + rings, + c: CycleBit::new(true), + deq_p_seg: 0, + deq_p_trb: 0, + } + } + + fn new_rings() -> Vec> { + let mut v = Vec::new(); + for _ in 0..Self::max_num_of_erst() { + v.push(BoxWrapper::new_slice( + [0; 4], + MAX_NUM_OF_TRB_IN_QUEUE.into(), + )); + } + + v + } + + fn max_num_of_erst() -> u16 { + registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .event_ring_segment_table_max() + }) + } + + fn try_dequeue(&mut self) -> Option { + if self.empty() { + None + } else { + self.dequeue() + } + } + + fn empty(&self) -> bool { + self.c_bit_of_next_trb() != self.c + } + + fn c_bit_of_next_trb(&self) -> CycleBit { + let t = self.rings[self.deq_p_seg][self.deq_p_trb]; + CycleBit::new(t[3].get_bit(0)) + } + + fn dequeue(&mut self) -> Option { + let t = self.get_next_trb().ok(); + self.increment(); + t + } + + fn get_next_trb(&self) -> Result { + let r = self.rings[self.deq_p_seg][self.deq_p_trb]; + let t = r.try_into(); + if t.is_err() { + warn!("Unrecognized ID: {}", r[3].get_bits(10..=15)); + } + t + } + + fn increment(&mut self) { + self.deq_p_trb += 1; + if self.deq_p_trb >= MAX_NUM_OF_TRB_IN_QUEUE.into() { + self.deq_p_trb = 0; + self.deq_p_seg += 1; + + if self.deq_p_seg >= self.num_of_erst() { + self.deq_p_seg = 0; + self.c.toggle(); + } + } + } + + fn num_of_erst(&self) -> usize { + self.rings.len() + } + + fn update_deq_p_with_xhci(&self) { + registers::handle(|r| { + let _ = &self; + + r.interrupter_register_set + .interrupter_mut(0) + .erdp + .update_volatile(|r| { + r.set_event_ring_dequeue_pointer(self.next_trb_addr().as_u64()) + }); + }); + } + + fn next_trb_addr(&self) -> PhysAddr { + self.rings[self.deq_p_seg].phys_addr() + trb::BYTES * self.deq_p_trb + } + + fn head_addrs(&self) -> Vec { + self.rings.iter().map(BoxWrapper::phys_addr).collect() + } +} + +struct SegTblInitializer<'a> { + ring: &'a mut Ring, +} +impl<'a> SegTblInitializer<'a> { + fn new(ring: &'a mut Ring) -> Self { + Self { ring } + } + + fn init(&mut self) { + self.write_addrs(); + self.register_tbl_sz(); + self.enable_event_ring(); + } + + fn write_addrs(&mut self) { + let addrs = self.ring.ring_addrs(); + for (entry, addr) in self.ring.iter_tbl_entries_mut().zip(addrs) { + entry.set(addr, MAX_NUM_OF_TRB_IN_QUEUE); + } + } + + fn register_tbl_sz(&mut self) { + registers::handle(|r| { + let l = self.tbl_len(); + + r.interrupter_register_set + .interrupter_mut(0) + .erstsz + .update_volatile(|r| r.set(l.try_into().unwrap())); + }) + } + + fn enable_event_ring(&mut self) { + registers::handle(|r| { + let a = self.tbl_addr(); + + r.interrupter_register_set + .interrupter_mut(0) + .erstba + .update_volatile(|r| { + r.set(a.as_u64()); + }) + }); + } + + fn tbl_addr(&self) -> PhysAddr { + self.ring.phys_addr_to_segment_table() + } + + fn tbl_len(&self) -> usize { + self.ring.segment_table.len() + } +} diff --git a/test/src/structures/ring/event/segment_table.rs b/test/src/structures/ring/event/segment_table.rs new file mode 100644 index 00000000..2489c033 --- /dev/null +++ b/test/src/structures/ring/event/segment_table.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use core::{ + ops::{Index, IndexMut}, + slice, +}; +use x86_64::PhysAddr; + +use crate::transition_helper::BoxWrapper; + +#[derive(Debug)] +pub struct SegmentTable(BoxWrapper<[Entry]>); +impl SegmentTable { + pub fn new(len: usize) -> Self { + Self(BoxWrapper::new_slice(Entry::null(), len)) + } + + pub fn phys_addr(&self) -> PhysAddr { + self.0.phys_addr() + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn iter_mut(&mut self) -> impl Iterator { + self.0.iter_mut() + } +} +impl Index for SegmentTable { + type Output = Entry; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} +impl IndexMut for SegmentTable { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} +impl<'a> IntoIterator for &'a mut SegmentTable { + type Item = &'a mut Entry; + type IntoIter = slice::IterMut<'a, Entry>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + +#[repr(C, packed)] +#[derive(Copy, Clone, Debug)] +pub struct Entry { + base_address: u64, + segment_size: u64, +} +impl Entry { + // Although the size of segment_size is u64, bits 16:63 are reserved. + pub fn set(&mut self, addr: PhysAddr, size: u16) { + self.base_address = addr.as_u64(); + self.segment_size = size.into(); + } + + fn null() -> Self { + Self { + base_address: 0, + segment_size: 0, + } + } +} diff --git a/test/src/structures/ring/mod.rs b/test/src/structures/ring/mod.rs new file mode 100644 index 00000000..ebd02e2b --- /dev/null +++ b/test/src/structures/ring/mod.rs @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub(crate) mod command; +pub(crate) mod event; +pub(crate) mod transfer; + +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub struct CycleBit(bool); +impl CycleBit { + pub fn new(val: bool) -> Self { + Self(val) + } + + fn toggle(&mut self) { + self.0 = !self.0; + } +} +impl From for bool { + fn from(cycle_bit: CycleBit) -> Self { + cycle_bit.0 + } +} diff --git a/test/src/structures/ring/transfer/mod.rs b/test/src/structures/ring/transfer/mod.rs new file mode 100644 index 00000000..94968cab --- /dev/null +++ b/test/src/structures/ring/transfer/mod.rs @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::CycleBit; +use crate::transition_helper::BoxWrapper; +use alloc::vec::Vec; +use trb::Link; +use x86_64::PhysAddr; +use xhci::ring::{trb, trb::transfer}; + +const SIZE_OF_RING: usize = 256; + +pub(crate) struct Ring { + raw: Raw, +} +impl Ring { + pub(crate) fn new() -> Self { + Self { raw: Raw::new() } + } + + pub(crate) fn phys_addr(&self) -> PhysAddr { + self.raw.phys_addr() + } + + pub(crate) fn enqueue(&mut self, trbs: &[transfer::Allowed]) -> Vec { + self.raw.enqueue_trbs(trbs) + } +} + +struct Raw { + ring: BoxWrapper<[[u32; 4]]>, + enq_p: usize, + c: CycleBit, +} +impl Raw { + fn new() -> Self { + Self { + ring: BoxWrapper::new_slice([0; 4], SIZE_OF_RING), + enq_p: 0, + c: CycleBit::new(true), + } + } + + fn enqueue_trbs(&mut self, trbs: &[transfer::Allowed]) -> Vec { + trbs.iter().map(|t| self.enqueue(*t)).collect() + } + + fn enqueue(&mut self, mut trb: transfer::Allowed) -> PhysAddr { + self.set_cycle_bit(&mut trb); + self.write_trb_on_memory(trb); + let addr_to_trb = self.addr_to_enqueue_ptr(); + self.increment_enqueue_ptr(); + + addr_to_trb + } + + fn write_trb_on_memory(&mut self, trb: transfer::Allowed) { + self.ring[self.enq_p] = trb.into_raw(); + } + + fn addr_to_enqueue_ptr(&self) -> PhysAddr { + self.phys_addr() + trb::BYTES * self.enq_p + } + + fn phys_addr(&self) -> PhysAddr { + self.ring.phys_addr() + } + + fn increment_enqueue_ptr(&mut self) { + self.enq_p += 1; + if self.enq_p < self.len() - 1 { + return; + } + + self.append_link_trb(); + self.move_enqueue_ptr_to_the_beginning(); + } + + fn len(&self) -> usize { + self.ring.len() + } + + fn append_link_trb(&mut self) { + let t = *Link::default().set_ring_segment_pointer(self.phys_addr().as_u64()); + let mut t = transfer::Allowed::Link(t); + self.set_cycle_bit(&mut t); + self.ring[self.enq_p] = t.into_raw(); + } + + fn move_enqueue_ptr_to_the_beginning(&mut self) { + self.enq_p = 0; + self.c.toggle(); + } + + fn set_cycle_bit(&self, trb: &mut transfer::Allowed) { + if self.c == CycleBit::new(true) { + trb.set_cycle_bit(); + } else { + trb.clear_cycle_bit(); + } + } +} diff --git a/test/src/structures/scratchpad.rs b/test/src/structures/scratchpad.rs new file mode 100644 index 00000000..2d576485 --- /dev/null +++ b/test/src/structures/scratchpad.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +use super::dcbaa; +use crate::registers; +use crate::transition_helper::BoxWrapper; +use alloc::vec::Vec; +use conquer_once::spin::OnceCell; +use core::convert::TryInto; +use os_units::Bytes; +use x86_64::PhysAddr; + +static SCRATCHPAD: OnceCell = OnceCell::uninit(); + +pub(crate) fn init() { + if Scratchpad::exists() { + init_static(); + } +} + +fn init_static() { + let mut scratchpad = Scratchpad::new(); + scratchpad.init(); + scratchpad.register_with_dcbaa(); + + SCRATCHPAD.init_once(|| scratchpad) +} + +struct Scratchpad { + arr: BoxWrapper<[PhysAddr]>, + bufs: Vec>, +} +impl Scratchpad { + fn new() -> Self { + let len: usize = Self::num_of_buffers().try_into().unwrap(); + + Self { + arr: BoxWrapper::new_slice(PhysAddr::zero(), len), + bufs: Vec::new(), + } + } + + fn exists() -> bool { + Self::num_of_buffers() > 0 + } + + fn init(&mut self) { + self.allocate_buffers(); + self.write_buffer_addresses(); + } + + fn register_with_dcbaa(&self) { + dcbaa::register(0, self.arr.phys_addr()); + } + + fn allocate_buffers(&mut self) { + for _ in 0..Self::num_of_buffers() { + // Allocate the double size of memory, then register the aligned address with the + // array. + let b = BoxWrapper::new_slice(0, Self::page_size().as_usize() * 2); + self.bufs.push(b); + } + } + + fn write_buffer_addresses(&mut self) { + let page_size: u64 = Self::page_size().as_usize().try_into().unwrap(); + for (x, buf) in self.arr.iter_mut().zip(self.bufs.iter()) { + *x = buf.phys_addr().align_up(page_size); + } + } + + fn num_of_buffers() -> u32 { + registers::handle(|r| { + r.capability + .hcsparams2 + .read_volatile() + .max_scratchpad_buffers() + }) + } + + fn page_size() -> Bytes { + Bytes::new(registers::handle(|r| r.operational.pagesize.read_volatile().get()).into()) + } +} diff --git a/test/src/transfer_ring.rs b/test/src/transfer_ring.rs deleted file mode 100644 index c4d8c9de..00000000 --- a/test/src/transfer_ring.rs +++ /dev/null @@ -1,26 +0,0 @@ -use alloc::boxed::Box; - -const NUM_OF_TRBS_IN_RING: usize = 16; - -pub struct TransferRingController { - ring: Box, -} -impl TransferRingController { - pub fn new() -> Self { - Self { - ring: Box::new(TransferRing::new()), - } - } - - pub fn head_addr(&self) -> u64 { - self.ring.as_ref() as *const _ as u64 - } -} - -#[repr(C, align(64))] -struct TransferRing([[u32; 4]; NUM_OF_TRBS_IN_RING]); -impl TransferRing { - fn new() -> Self { - Self([[0; 4]; NUM_OF_TRBS_IN_RING]) - } -} diff --git a/test/src/transition_helper.rs b/test/src/transition_helper.rs new file mode 100644 index 00000000..f4ed5a5c --- /dev/null +++ b/test/src/transition_helper.rs @@ -0,0 +1,61 @@ +use alloc::boxed::Box; +use alloc::vec; +use core::fmt; +use core::fmt::Debug; +use core::fmt::Formatter; +use core::ops::Deref; +use core::ops::DerefMut; +use os_units::Bytes; +use x86_64::PhysAddr; + +pub struct BoxWrapper { + inner: Box, + bytes: u64, +} +impl BoxWrapper { + pub fn new(inner: Box, bytes: u64) -> Self { + Self { inner, bytes } + } + + pub fn phys_addr(&self) -> PhysAddr { + PhysAddr::new(self.inner.as_ref() as *const T as *const u8 as u64) + } + + pub fn bytes(&self) -> Bytes { + Bytes::new(self.bytes as _) + } +} +impl BoxWrapper<[T]> { + pub fn new_slice(init: T, len: usize) -> Self { + Self::new( + vec![init; len].into_boxed_slice(), + (len * core::mem::size_of::()) as u64, + ) + } +} +impl Deref for BoxWrapper { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.inner + } +} +impl DerefMut for BoxWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} +impl From for BoxWrapper { + fn from(inner: T) -> Self { + Self::new(Box::new(inner), core::mem::size_of::() as u64) + } +} +impl Default for BoxWrapper { + fn default() -> Self { + Self::new(Box::new(T::default()), core::mem::size_of::() as u64) + } +} +impl Debug for BoxWrapper { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/test/src/xhc.rs b/test/src/xhc.rs index ed8b2b99..aabd06e2 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,45 +1,29 @@ -use crate::command_ring; -use crate::dcbaa; -use crate::event; -use crate::registers; -use crate::scratchpat; -use qemu_print::qemu_println; - -/// Initializes the host controller according to 4.2 of xHCI spec. -/// -/// Note that we do not enable interrupts as it is optional and for simplicity. -pub fn init() { - qemu_println!("Initializing xHC..."); - - wait_until_controller_is_ready(); - stop(); - reset(); - set_num_of_enabled_slots(); +// SPDX-License-Identifier: GPL-3.0-or-later - event::init(); - command_ring::init(); - dcbaa::init(); - scratchpat::init(); +use super::structures::{extended_capabilities, registers}; +use xhci::extended_capabilities::ExtendedCapability; - run(); - ensure_no_error_occurs(); +pub(super) fn exists() -> bool { + super::iter_xhc().next().is_some() +} - qemu_println!("xHC is initialized."); +pub(crate) fn init() { + get_ownership_from_bios(); + stop_and_reset(); + set_num_of_enabled_slots(); } -fn run() { +pub(crate) fn run() { registers::handle(|r| { - let op = &mut r.operational; - - op.usbcmd.update_volatile(|u| { + let o = &mut r.operational; + o.usbcmd.update_volatile(|u| { u.set_run_stop(); }); - - while op.usbsts.read_volatile().hc_halted() {} + while o.usbsts.read_volatile().hc_halted() {} }); } -fn ensure_no_error_occurs() { +pub(crate) fn ensure_no_error_occurs() { registers::handle(|r| { let s = r.operational.usbsts.read_volatile(); @@ -49,107 +33,88 @@ fn ensure_no_error_occurs() { "An error occured on the host system." ); assert!(!s.host_controller_error(), "An error occured on the xHC."); - }) + }); } -fn wait_until_controller_is_ready() { - registers::handle( - |r| { - while r.operational.usbsts.read_volatile().controller_not_ready() {} - }, - ); +fn get_ownership_from_bios() { + if let Some(iter) = extended_capabilities::iter() { + for c in iter.filter_map(Result::ok) { + if let ExtendedCapability::UsbLegacySupport(mut u) = c { + let l = &mut u.usblegsup; + l.update_volatile(|s| { + s.set_hc_os_owned_semaphore(); + }); + + while l.read_volatile().hc_bios_owned_semaphore() + || !l.read_volatile().hc_os_owned_semaphore() + {} + } + } + } } -fn stop() { - Stopper::new().stop(); +fn stop_and_reset() { + stop(); + wait_until_halt(); + reset(); } -fn reset() { - Resetter::new().reset(); +fn stop() { + registers::handle(|r| { + r.operational.usbcmd.update_volatile(|u| { + u.clear_run_stop(); + }); + }) } -fn set_num_of_enabled_slots() { - SlotNumberSetter::new().set(); +fn wait_until_halt() { + registers::handle(|r| while !r.operational.usbsts.read_volatile().hc_halted() {}) } -struct Stopper {} -impl Stopper { - fn new() -> Self { - Self {} - } - - fn stop(&mut self) { - registers::handle(|r| { - let op = &mut r.operational; - - op.usbcmd.update_volatile(|u| { - u.clear_run_stop(); - }); - - while !op.usbsts.read_volatile().hc_halted() {} - }) - } +fn reset() { + start_resetting(); + wait_until_reset_completed(); + wait_until_ready(); } -struct Resetter {} -impl Resetter { - fn new() -> Self { - Self {} - } - - fn reset(&mut self) { - self.start_resetting(); - self.wait_until_reset_completed(); - self.wait_until_ready(); - } - - fn start_resetting(&mut self) { - registers::handle(|r| { - r.operational.usbcmd.update_volatile(|u| { - u.set_host_controller_reset(); - }); +fn start_resetting() { + registers::handle(|r| { + r.operational.usbcmd.update_volatile(|u| { + u.set_host_controller_reset(); }) - } - - fn wait_until_reset_completed(&self) { - registers::handle( - |r| { - while r.operational.usbcmd.read_volatile().host_controller_reset() {} - }, - ) - } - - fn wait_until_ready(&self) { - registers::handle( - |r| { - while r.operational.usbsts.read_volatile().controller_not_ready() {} - }, - ) - } + }) } -struct SlotNumberSetter {} -impl SlotNumberSetter { - fn new() -> Self { - Self {} - } +fn wait_until_reset_completed() { + registers::handle( + |r| { + while r.operational.usbcmd.read_volatile().host_controller_reset() {} + }, + ) +} - fn set(&mut self) { - let n = self.number_of_slots(); +fn wait_until_ready() { + registers::handle( + |r| { + while r.operational.usbsts.read_volatile().controller_not_ready() {} + }, + ) +} - registers::handle(|r| { - r.operational.config.update_volatile(|c| { - c.set_max_device_slots_enabled(n); - }); - }) - } +fn set_num_of_enabled_slots() { + let n = num_of_device_slots(); + registers::handle(|r| { + r.operational.config.update_volatile(|c| { + c.set_max_device_slots_enabled(n); + }); + }) +} - fn number_of_slots(&self) -> u8 { - registers::handle(|r| { - r.capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() - }) - } +fn num_of_device_slots() -> u8 { + registers::handle(|r| { + r.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() + }) } diff --git a/test/x86_64-unknown-ramen.json b/test/x86_64-unknown-ramen.json new file mode 100644 index 00000000..5ceb8be5 --- /dev/null +++ b/test/x86_64-unknown-ramen.json @@ -0,0 +1,22 @@ +{ + "arch": "x86_64", + "":"See http://llvm.org/docs/LangRef.html#data-layout to know what data-layout represents.", + "data-layout": "e-m:e-i64:64-n8:16:32:64-S128", + "llvm-target": "x86_64-unknown-none", + "executables": true, + "features": "-sse,+soft-float", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "code-model": "kernel", + "relocation-model": "static", + "archive-format": "gnu", + "target-env": "gnu", + "no-compiler-rt": false, + "panic-strategy": "abort", + "linker-flavor": "ld", + "linker-is-gnu": true, + "disable-redzone": true, + "eliminate-frame-pointer": false +} From 831075b25d9826ec7a103d14845311eab15a3dbb Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:14:57 +0900 Subject: [PATCH 089/115] Logger --- test/src/main.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/src/main.rs b/test/src/main.rs index f3e1a617..227d4c90 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -40,6 +40,7 @@ mod xhc; #[uefi::entry] fn main(h: Handle, st: SystemTable) -> uefi::Status { + init_logger(); init(); let mut executor = Executor::new(); @@ -106,3 +107,25 @@ fn panic(info: &core::panic::PanicInfo) -> ! { handler.exit_failure(); } + +struct MyLogger; +impl log::Log for MyLogger { + fn enabled(&self, _: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + if self.enabled(record.metadata()) { + qemu_println!("[{}] {}", record.level(), record.args()); + } + } + + fn flush(&self) {} +} + +static LOGGER: MyLogger = MyLogger; + +fn init_logger() { + log::set_logger(&LOGGER).unwrap(); + log::set_max_level(log::LevelFilter::Info); +} From 069e0118cf1b82dcae970a8295c6ab25f0585475 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:17:50 +0900 Subject: [PATCH 090/115] Split --- test/src/logger.rs | 23 +++++++++++++++++++++++ test/src/main.rs | 25 ++----------------------- 2 files changed, 25 insertions(+), 23 deletions(-) create mode 100644 test/src/logger.rs diff --git a/test/src/logger.rs b/test/src/logger.rs new file mode 100644 index 00000000..48dfed67 --- /dev/null +++ b/test/src/logger.rs @@ -0,0 +1,23 @@ +use qemu_print::qemu_println; + +static LOGGER: MyLogger = MyLogger; + +struct MyLogger; +impl log::Log for MyLogger { + fn enabled(&self, _: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + if self.enabled(record.metadata()) { + qemu_println!("[{}] {}", record.level(), record.args()); + } + } + + fn flush(&self) {} +} + +pub fn init() { + log::set_logger(&LOGGER).unwrap(); + log::set_max_level(log::LevelFilter::Info); +} diff --git a/test/src/main.rs b/test/src/main.rs index 227d4c90..e01af2e0 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -30,6 +30,7 @@ pub(crate) type FuturelockGuard<'a, T> = GenericMutexGuard<'a, RawSpinlock, T>; mod allocator; mod exchanger; +mod logger; mod mapper; mod multitask; mod pci; @@ -40,7 +41,7 @@ mod xhc; #[uefi::entry] fn main(h: Handle, st: SystemTable) -> uefi::Status { - init_logger(); + logger::init(); init(); let mut executor = Executor::new(); @@ -107,25 +108,3 @@ fn panic(info: &core::panic::PanicInfo) -> ! { handler.exit_failure(); } - -struct MyLogger; -impl log::Log for MyLogger { - fn enabled(&self, _: &log::Metadata) -> bool { - true - } - - fn log(&self, record: &log::Record) { - if self.enabled(record.metadata()) { - qemu_println!("[{}] {}", record.level(), record.args()); - } - } - - fn flush(&self) {} -} - -static LOGGER: MyLogger = MyLogger; - -fn init_logger() { - log::set_logger(&LOGGER).unwrap(); - log::set_max_level(log::LevelFilter::Info); -} From 1c8a52afc0e4f3331b06dfbaf29f4d0c8e1dc57d Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:18:38 +0900 Subject: [PATCH 091/115] Remove license comments --- test/src/exchanger/command.rs | 1 - test/src/exchanger/mod.rs | 1 - test/src/exchanger/receiver.rs | 1 - test/src/exchanger/transfer.rs | 1 - test/src/main.rs | 1 - test/src/pci/config/bar.rs | 1 - test/src/pci/config/common.rs | 1 - test/src/pci/config/mod.rs | 1 - test/src/pci/config/type_spec/mod.rs | 1 - test/src/pci/config/type_spec/non_bridge.rs | 1 - test/src/pci/mod.rs | 1 - test/src/port/class_driver/keyboard.rs | 1 - test/src/port/class_driver/mass_storage/mod.rs | 1 - .../port/class_driver/mass_storage/scsi/command_data_block.rs | 1 - test/src/port/class_driver/mass_storage/scsi/mod.rs | 1 - test/src/port/class_driver/mass_storage/scsi/response.rs | 1 - test/src/port/class_driver/mod.rs | 1 - test/src/port/class_driver/mouse.rs | 1 - test/src/port/endpoint.rs | 1 - test/src/port/init/descriptor_fetcher.rs | 1 - test/src/port/init/endpoints_initializer.rs | 1 - test/src/port/init/fully_operational.rs | 1 - test/src/port/init/max_packet_size_setter.rs | 1 - test/src/port/init/mod.rs | 1 - test/src/port/init/resetter.rs | 1 - test/src/port/init/slot_structures_initializer.rs | 1 - test/src/port/mod.rs | 1 - test/src/port/spawner.rs | 1 - test/src/structures/context.rs | 1 - test/src/structures/dcbaa.rs | 1 - test/src/structures/descriptor.rs | 1 - test/src/structures/extended_capabilities.rs | 1 - test/src/structures/mod.rs | 1 - test/src/structures/registers.rs | 1 - test/src/structures/ring/command/mod.rs | 1 - test/src/structures/ring/event/mod.rs | 1 - test/src/structures/ring/event/segment_table.rs | 1 - test/src/structures/ring/mod.rs | 1 - test/src/structures/ring/transfer/mod.rs | 1 - test/src/structures/scratchpad.rs | 1 - test/src/xhc.rs | 1 - 41 files changed, 41 deletions(-) diff --git a/test/src/exchanger/command.rs b/test/src/exchanger/command.rs index 981bc909..e98246e1 100644 --- a/test/src/exchanger/command.rs +++ b/test/src/exchanger/command.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::{ super::structures::ring::command, diff --git a/test/src/exchanger/mod.rs b/test/src/exchanger/mod.rs index 0df9546c..901df1a5 100644 --- a/test/src/exchanger/mod.rs +++ b/test/src/exchanger/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later pub(crate) mod command; pub(crate) mod receiver; diff --git a/test/src/exchanger/receiver.rs b/test/src/exchanger/receiver.rs index ecfff20e..32d7357d 100644 --- a/test/src/exchanger/receiver.rs +++ b/test/src/exchanger/receiver.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use alloc::{collections::BTreeMap, sync::Arc}; use conquer_once::spin::Lazy; diff --git a/test/src/exchanger/transfer.rs b/test/src/exchanger/transfer.rs index a70c1663..cc36b2d1 100644 --- a/test/src/exchanger/transfer.rs +++ b/test/src/exchanger/transfer.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::receiver::{self, ReceiveFuture}; use crate::structures::{descriptor, registers, ring::transfer}; diff --git a/test/src/main.rs b/test/src/main.rs index e01af2e0..92e61aba 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later #![no_std] #![no_main] diff --git a/test/src/pci/config/bar.rs b/test/src/pci/config/bar.rs index dfdfd677..b8a8dc7b 100644 --- a/test/src/pci/config/bar.rs +++ b/test/src/pci/config/bar.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::RegisterIndex; use core::{ diff --git a/test/src/pci/config/common.rs b/test/src/pci/config/common.rs index 274ec347..b91fb93d 100644 --- a/test/src/pci/config/common.rs +++ b/test/src/pci/config/common.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::{RegisterIndex, Registers}; use bit_field::BitField; diff --git a/test/src/pci/config/mod.rs b/test/src/pci/config/mod.rs index dec4b6f1..43a5bd45 100644 --- a/test/src/pci/config/mod.rs +++ b/test/src/pci/config/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later pub(crate) mod bar; mod common; diff --git a/test/src/pci/config/type_spec/mod.rs b/test/src/pci/config/type_spec/mod.rs index abf4555e..976c45d2 100644 --- a/test/src/pci/config/type_spec/mod.rs +++ b/test/src/pci/config/type_spec/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later mod non_bridge; diff --git a/test/src/pci/config/type_spec/non_bridge.rs b/test/src/pci/config/type_spec/non_bridge.rs index 27e3cac3..8021bbbc 100644 --- a/test/src/pci/config/type_spec/non_bridge.rs +++ b/test/src/pci/config/type_spec/non_bridge.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::{bar, Bar, RegisterIndex, Registers}; use log::debug; diff --git a/test/src/pci/mod.rs b/test/src/pci/mod.rs index 3621b8a1..408ac9d3 100644 --- a/test/src/pci/mod.rs +++ b/test/src/pci/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later pub(crate) mod config; diff --git a/test/src/port/class_driver/keyboard.rs b/test/src/port/class_driver/keyboard.rs index c6948252..c42c27d6 100644 --- a/test/src/port/class_driver/keyboard.rs +++ b/test/src/port/class_driver/keyboard.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use crate::{ port::init::fully_operational::FullyOperational, diff --git a/test/src/port/class_driver/mass_storage/mod.rs b/test/src/port/class_driver/mass_storage/mod.rs index 54bd7ed4..e7f36285 100644 --- a/test/src/port/class_driver/mass_storage/mod.rs +++ b/test/src/port/class_driver/mass_storage/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later mod scsi; diff --git a/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs b/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs index 16d8a765..4007c4e8 100644 --- a/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs +++ b/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use byteorder::{BigEndian, ByteOrder}; diff --git a/test/src/port/class_driver/mass_storage/scsi/mod.rs b/test/src/port/class_driver/mass_storage/scsi/mod.rs index e55e887d..327ce1ac 100644 --- a/test/src/port/class_driver/mass_storage/scsi/mod.rs +++ b/test/src/port/class_driver/mass_storage/scsi/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later pub(super) mod command_data_block; pub(super) mod response; diff --git a/test/src/port/class_driver/mass_storage/scsi/response.rs b/test/src/port/class_driver/mass_storage/scsi/response.rs index a753b02e..1674d7d8 100644 --- a/test/src/port/class_driver/mass_storage/scsi/response.rs +++ b/test/src/port/class_driver/mass_storage/scsi/response.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use byteorder::{BigEndian, ByteOrder}; use core::fmt; diff --git a/test/src/port/class_driver/mod.rs b/test/src/port/class_driver/mod.rs index 74bb09e5..a7e007b7 100644 --- a/test/src/port/class_driver/mod.rs +++ b/test/src/port/class_driver/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later pub(crate) mod keyboard; pub(super) mod mass_storage; diff --git a/test/src/port/class_driver/mouse.rs b/test/src/port/class_driver/mouse.rs index 110e61fd..af10c901 100644 --- a/test/src/port/class_driver/mouse.rs +++ b/test/src/port/class_driver/mouse.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use crate::{ port::init::fully_operational::FullyOperational, diff --git a/test/src/port/endpoint.rs b/test/src/port/endpoint.rs index d9e1e7f6..28471186 100644 --- a/test/src/port/endpoint.rs +++ b/test/src/port/endpoint.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use crate::{exchanger::transfer, structures::descriptor, transition_helper::BoxWrapper}; use x86_64::PhysAddr; diff --git a/test/src/port/init/descriptor_fetcher.rs b/test/src/port/init/descriptor_fetcher.rs index e97a3568..bd33d8ec 100644 --- a/test/src/port/init/descriptor_fetcher.rs +++ b/test/src/port/init/descriptor_fetcher.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::{ endpoints_initializer::EndpointsInitializer, max_packet_size_setter::MaxPacketSizeSetter, diff --git a/test/src/port/init/endpoints_initializer.rs b/test/src/port/init/endpoints_initializer.rs index e1e5373d..08e50bbe 100644 --- a/test/src/port/init/endpoints_initializer.rs +++ b/test/src/port/init/endpoints_initializer.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::{descriptor_fetcher::DescriptorFetcher, fully_operational::FullyOperational}; use crate::{ diff --git a/test/src/port/init/fully_operational.rs b/test/src/port/init/fully_operational.rs index 2141c496..1f92aaef 100644 --- a/test/src/port/init/fully_operational.rs +++ b/test/src/port/init/fully_operational.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::endpoints_initializer::EndpointsInitializer; use crate::{ diff --git a/test/src/port/init/max_packet_size_setter.rs b/test/src/port/init/max_packet_size_setter.rs index 9980c71f..a21f572e 100644 --- a/test/src/port/init/max_packet_size_setter.rs +++ b/test/src/port/init/max_packet_size_setter.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::{ descriptor_fetcher::DescriptorFetcher, slot_structures_initializer::SlotStructuresInitializer, diff --git a/test/src/port/init/mod.rs b/test/src/port/init/mod.rs index 8e151bb2..af46976c 100644 --- a/test/src/port/init/mod.rs +++ b/test/src/port/init/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use fully_operational::FullyOperational; use resetter::Resetter; diff --git a/test/src/port/init/resetter.rs b/test/src/port/init/resetter.rs index fa8dcd92..4f1e1256 100644 --- a/test/src/port/init/resetter.rs +++ b/test/src/port/init/resetter.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::slot_structures_initializer::SlotStructuresInitializer; use crate::structures::registers; diff --git a/test/src/port/init/slot_structures_initializer.rs b/test/src/port/init/slot_structures_initializer.rs index 6d256c34..33a8c84e 100644 --- a/test/src/port/init/slot_structures_initializer.rs +++ b/test/src/port/init/slot_structures_initializer.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::{max_packet_size_setter::MaxPacketSizeSetter, resetter::Resetter}; use crate::{ diff --git a/test/src/port/mod.rs b/test/src/port/mod.rs index d771da1c..61c94bde 100644 --- a/test/src/port/mod.rs +++ b/test/src/port/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::structures::registers; use crate::multitask::{self, task::Task}; diff --git a/test/src/port/spawner.rs b/test/src/port/spawner.rs index ae320553..416e5ef4 100644 --- a/test/src/port/spawner.rs +++ b/test/src/port/spawner.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use crate::multitask; use alloc::{vec, vec::Vec}; diff --git a/test/src/structures/context.rs b/test/src/structures/context.rs index 0597d0a4..f6f0b59e 100644 --- a/test/src/structures/context.rs +++ b/test/src/structures/context.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use crate::transition_helper::BoxWrapper; diff --git a/test/src/structures/dcbaa.rs b/test/src/structures/dcbaa.rs index 0713645d..efbd505a 100644 --- a/test/src/structures/dcbaa.rs +++ b/test/src/structures/dcbaa.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use crate::transition_helper::BoxWrapper; diff --git a/test/src/structures/descriptor.rs b/test/src/structures/descriptor.rs index d9abbe92..279c312f 100644 --- a/test/src/structures/descriptor.rs +++ b/test/src/structures/descriptor.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use bit_field::BitField; use core::{convert::TryInto, ptr}; diff --git a/test/src/structures/extended_capabilities.rs b/test/src/structures/extended_capabilities.rs index 5bbcb368..432df490 100644 --- a/test/src/structures/extended_capabilities.rs +++ b/test/src/structures/extended_capabilities.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::registers; use crate::mapper::Mapper; diff --git a/test/src/structures/mod.rs b/test/src/structures/mod.rs index e2538cba..31cdc763 100644 --- a/test/src/structures/mod.rs +++ b/test/src/structures/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later pub(crate) mod context; pub(crate) mod dcbaa; diff --git a/test/src/structures/registers.rs b/test/src/structures/registers.rs index a44655c5..eff684dd 100644 --- a/test/src/structures/registers.rs +++ b/test/src/structures/registers.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use crate::mapper::Mapper; use conquer_once::spin::OnceCell; diff --git a/test/src/structures/ring/command/mod.rs b/test/src/structures/ring/command/mod.rs index 8f87f587..9d736bf9 100644 --- a/test/src/structures/ring/command/mod.rs +++ b/test/src/structures/ring/command/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::CycleBit; use crate::{registers, transition_helper::BoxWrapper}; diff --git a/test/src/structures/ring/event/mod.rs b/test/src/structures/ring/event/mod.rs index 41a43648..8fbad3a6 100644 --- a/test/src/structures/ring/event/mod.rs +++ b/test/src/structures/ring/event/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::CycleBit; use crate::{exchanger::receiver, port, structures::registers, transition_helper::BoxWrapper}; diff --git a/test/src/structures/ring/event/segment_table.rs b/test/src/structures/ring/event/segment_table.rs index 2489c033..9140d5b7 100644 --- a/test/src/structures/ring/event/segment_table.rs +++ b/test/src/structures/ring/event/segment_table.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use core::{ ops::{Index, IndexMut}, diff --git a/test/src/structures/ring/mod.rs b/test/src/structures/ring/mod.rs index ebd02e2b..e8500f23 100644 --- a/test/src/structures/ring/mod.rs +++ b/test/src/structures/ring/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later pub(crate) mod command; pub(crate) mod event; diff --git a/test/src/structures/ring/transfer/mod.rs b/test/src/structures/ring/transfer/mod.rs index 94968cab..bdc24079 100644 --- a/test/src/structures/ring/transfer/mod.rs +++ b/test/src/structures/ring/transfer/mod.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::CycleBit; use crate::transition_helper::BoxWrapper; diff --git a/test/src/structures/scratchpad.rs b/test/src/structures/scratchpad.rs index 2d576485..a72200da 100644 --- a/test/src/structures/scratchpad.rs +++ b/test/src/structures/scratchpad.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::dcbaa; use crate::registers; diff --git a/test/src/xhc.rs b/test/src/xhc.rs index aabd06e2..17dcd021 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-3.0-or-later use super::structures::{extended_capabilities, registers}; use xhci::extended_capabilities::ExtendedCapability; From debc0380d8377cf3c96e6646261703bff794c8fc Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:21:56 +0900 Subject: [PATCH 092/115] Init allocators --- test/src/main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index 92e61aba..57e8debc 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -1,4 +1,3 @@ - #![no_std] #![no_main] // A workaround for the `derive_builder` crate. @@ -19,7 +18,7 @@ use structures::{ scratchpad, }; use uefi::{ - table::{Boot, SystemTable}, + table::{boot::MemoryType, Boot, SystemTable}, Handle, }; use x86_64::PhysAddr; @@ -40,7 +39,11 @@ mod xhc; #[uefi::entry] fn main(h: Handle, st: SystemTable) -> uefi::Status { + let (_, mmap) = st.exit_boot_services(MemoryType::LOADER_DATA); + logger::init(); + allocator::init(mmap); + init(); let mut executor = Executor::new(); From bf1d0891362c9e4302c58e4c2123748ac99b4c8f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:23:42 +0900 Subject: [PATCH 093/115] Log everything --- test/src/logger.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/src/logger.rs b/test/src/logger.rs index 48dfed67..42620493 100644 --- a/test/src/logger.rs +++ b/test/src/logger.rs @@ -9,9 +9,7 @@ impl log::Log for MyLogger { } fn log(&self, record: &log::Record) { - if self.enabled(record.metadata()) { - qemu_println!("[{}] {}", record.level(), record.args()); - } + qemu_println!("[{}] {}", record.level(), record.args()); } fn flush(&self) {} From 354dabfc5178dc99684c67bb5ba39c847483b87f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:23:54 +0900 Subject: [PATCH 094/115] Log everything --- test/src/logger.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/src/logger.rs b/test/src/logger.rs index 42620493..fd469084 100644 --- a/test/src/logger.rs +++ b/test/src/logger.rs @@ -17,5 +17,4 @@ impl log::Log for MyLogger { pub fn init() { log::set_logger(&LOGGER).unwrap(); - log::set_max_level(log::LevelFilter::Info); } From a1e71fdf1ec1de7a4e0a31b71f0d09f64fbfa4ef Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:24:51 +0900 Subject: [PATCH 095/115] Assert the existence of xHC --- test/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index 57e8debc..7bf12341 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -44,6 +44,8 @@ fn main(h: Handle, st: SystemTable) -> uefi::Status { logger::init(); allocator::init(mmap); + assert!(xhc::exists(), "xHC does not exist."); + init(); let mut executor = Executor::new(); @@ -51,9 +53,7 @@ fn main(h: Handle, st: SystemTable) -> uefi::Status { } pub(crate) fn init() { - if xhc::exists() { - init_and_spawn_tasks(); - } + init_and_spawn_tasks(); } fn init_statics() { From 8b9f5e55df4e7d688c6a3a31ef70fcf5749c85eb Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:29:09 +0900 Subject: [PATCH 096/115] Use underscore --- test/src/mapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/mapper.rs b/test/src/mapper.rs index b1a10014..b5f3cd5f 100644 --- a/test/src/mapper.rs +++ b/test/src/mapper.rs @@ -8,5 +8,5 @@ impl xhci::accessor::Mapper for Mapper { NonZeroUsize::new(physical_address).expect("physical_address is zero") } - fn unmap(&mut self, _virtual_address: usize, _size: usize) {} + fn unmap(&mut self, _: usize, _: usize) {} } From d126005ea3388cadabe1df683237808b232972da Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 17:40:39 +0900 Subject: [PATCH 097/115] Docs --- test/src/structures/extended_capabilities.rs | 4 +++- test/src/structures/registers.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/src/structures/extended_capabilities.rs b/test/src/structures/extended_capabilities.rs index 432df490..f457c7aa 100644 --- a/test/src/structures/extended_capabilities.rs +++ b/test/src/structures/extended_capabilities.rs @@ -1,4 +1,3 @@ - use super::registers; use crate::mapper::Mapper; use conquer_once::spin::OnceCell; @@ -10,6 +9,9 @@ use xhci::{extended_capabilities, ExtendedCapability}; static EXTENDED_CAPABILITIES: OnceCell>>> = OnceCell::uninit(); +/// # Safety +/// +/// `mmio_base` must be the correct one. pub(crate) unsafe fn init(mmio_base: PhysAddr) { let hccparams1 = registers::handle(|r| r.capability.hccparams1.read_volatile()); diff --git a/test/src/structures/registers.rs b/test/src/structures/registers.rs index eff684dd..c12d3f90 100644 --- a/test/src/structures/registers.rs +++ b/test/src/structures/registers.rs @@ -1,4 +1,3 @@ - use crate::mapper::Mapper; use conquer_once::spin::OnceCell; use core::convert::TryInto; @@ -8,6 +7,9 @@ use xhci::Registers; static REGISTERS: OnceCell>> = OnceCell::uninit(); +/// # Safety +/// +/// `mmio_base` must be the correct one. pub(crate) unsafe fn init(mmio_base: PhysAddr) { let mmio_base: usize = mmio_base.as_u64().try_into().unwrap(); From ca63ef8982921a5e4ef0678398cbe2761230822c Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 18:00:50 +0900 Subject: [PATCH 098/115] Ownership --- test/src/main.rs | 6 ++++++ test/src/xhc.rs | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index 7bf12341..c1c5f634 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -72,6 +72,12 @@ fn init_and_spawn_tasks() { let mut event_ring = event::Ring::new(); let command_ring = Arc::new(Spinlock::new(command::Ring::new())); + // In some cases, an OS may need to get ownership of the xHC from the BIOS. + // See 4.22.1 of xHCI spec. + // + // This is not necessary on QEMU, but this line is left for a reference. + xhc::get_ownership_from_bios(); + xhc::init(); event_ring.init(); diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 17dcd021..3f6444a2 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,4 +1,3 @@ - use super::structures::{extended_capabilities, registers}; use xhci::extended_capabilities::ExtendedCapability; @@ -35,7 +34,7 @@ pub(crate) fn ensure_no_error_occurs() { }); } -fn get_ownership_from_bios() { +pub(crate) fn get_ownership_from_bios() { if let Some(iter) = extended_capabilities::iter() { for c in iter.filter_map(Result::ok) { if let ExtendedCapability::UsbLegacySupport(mut u) = c { From f59d93a91d08a4e16450a8a0a8d372e2ad01c62f Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 18:07:15 +0900 Subject: [PATCH 099/115] Static --- test/src/exchanger/command.rs | 9 ++++++--- test/src/main.rs | 4 +--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/src/exchanger/command.rs b/test/src/exchanger/command.rs index e98246e1..0835856d 100644 --- a/test/src/exchanger/command.rs +++ b/test/src/exchanger/command.rs @@ -1,4 +1,3 @@ - use super::{ super::structures::ring::command, receiver::{self, ReceiveFuture}, @@ -15,9 +14,13 @@ use xhci::ring::trb::{command as command_trb, event}; static SENDER: OnceCell> = OnceCell::uninit(); -pub(crate) fn init(r: Arc>) { +pub(crate) fn init() { + let ring = Arc::new(Spinlock::new(command::Ring::new())); + + ring.lock().init(); + SENDER - .try_init_once(|| Futurelock::new(Sender::new(r), true)) + .try_init_once(|| Futurelock::new(Sender::new(ring), true)) .expect("`Sender` is initialized more than once.") } diff --git a/test/src/main.rs b/test/src/main.rs index c1c5f634..a1ad88bd 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -70,7 +70,6 @@ fn init_and_spawn_tasks() { init_statics(); let mut event_ring = event::Ring::new(); - let command_ring = Arc::new(Spinlock::new(command::Ring::new())); // In some cases, an OS may need to get ownership of the xHC from the BIOS. // See 4.22.1 of xHCI spec. @@ -81,10 +80,9 @@ fn init_and_spawn_tasks() { xhc::init(); event_ring.init(); - command_ring.lock().init(); dcbaa::init(); scratchpad::init(); - exchanger::command::init(command_ring); + exchanger::command::init(); xhc::run(); xhc::ensure_no_error_occurs(); From 56ad667e2a11640a281d1d844038e896875f41e3 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 18:12:56 +0900 Subject: [PATCH 100/115] Static --- test/src/main.rs | 10 ++++------ test/src/structures/ring/event/mod.rs | 26 +++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index a1ad88bd..c6bd3cd4 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -69,8 +69,6 @@ fn init_statics() { fn init_and_spawn_tasks() { init_statics(); - let mut event_ring = event::Ring::new(); - // In some cases, an OS may need to get ownership of the xHC from the BIOS. // See 4.22.1 of xHCI spec. // @@ -79,21 +77,21 @@ fn init_and_spawn_tasks() { xhc::init(); - event_ring.init(); dcbaa::init(); scratchpad::init(); exchanger::command::init(); + event::init(); xhc::run(); xhc::ensure_no_error_occurs(); - spawn_tasks(event_ring); + spawn_tasks(); } -fn spawn_tasks(e: event::Ring) { +fn spawn_tasks() { port::spawn_all_connected_port_tasks(); - multitask::add(Task::new_poll(event::task(e))); + multitask::add(Task::new_poll(event::task())); } fn iter_xhc() -> impl Iterator { diff --git a/test/src/structures/ring/event/mod.rs b/test/src/structures/ring/event/mod.rs index 8fbad3a6..6118e7ae 100644 --- a/test/src/structures/ring/event/mod.rs +++ b/test/src/structures/ring/event/mod.rs @@ -1,8 +1,8 @@ - use super::CycleBit; use crate::{exchanger::receiver, port, structures::registers, transition_helper::BoxWrapper}; use alloc::vec::Vec; use bit_field::BitField; +use conquer_once::spin::OnceCell; use core::{ convert::TryInto, pin::Pin, @@ -11,6 +11,7 @@ use core::{ use futures_util::{stream::Stream, StreamExt}; use log::{debug, info, warn}; use segment_table::SegmentTable; +use spinning_top::Spinlock; use x86_64::{ structures::paging::{PageSize, Size4KiB}, PhysAddr, @@ -19,9 +20,28 @@ use xhci::ring::{trb, trb::event}; mod segment_table; -pub(crate) async fn task(mut ring: Ring) { +static EVENT_RING: OnceCell> = OnceCell::uninit(); + +pub fn init() { + let ring = Spinlock::new(Ring::new()); + ring.lock().init(); + + EVENT_RING + .try_init_once(|| ring) + .expect("`EVENT_RING` is initialized more than once."); +} + +pub(crate) async fn task() { debug!("This is the Event ring task."); - while let Some(trb) = ring.next().await { + + while let Some(trb) = EVENT_RING + .get() + .expect("The event ring is not initialized") + .try_lock() + .expect("Failed to lock the event ring.") + .next() + .await + { info!("TRB: {:?}", trb); if let event::Allowed::CommandCompletion(_) = trb { receiver::receive(trb); From e08269d6c93fa2fa92ef398a9b63d073132c3671 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 18:55:23 +0900 Subject: [PATCH 101/115] Doc --- test/src/main.rs | 9 --------- test/src/xhc.rs | 14 +++++++++++++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/test/src/main.rs b/test/src/main.rs index c6bd3cd4..51f27d29 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -5,7 +5,6 @@ extern crate alloc; -use alloc::sync::Arc; use futures_intrusive::sync::{GenericMutex, GenericMutexGuard}; use multitask::{executor::Executor, task::Task}; use pci::config::bar; @@ -77,14 +76,6 @@ fn init_and_spawn_tasks() { xhc::init(); - dcbaa::init(); - scratchpad::init(); - exchanger::command::init(); - event::init(); - - xhc::run(); - xhc::ensure_no_error_occurs(); - spawn_tasks(); } diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 3f6444a2..25e8764e 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -1,14 +1,26 @@ use super::structures::{extended_capabilities, registers}; +use crate::{ + exchanger, + structures::{dcbaa, ring::event, scratchpad}, +}; use xhci::extended_capabilities::ExtendedCapability; pub(super) fn exists() -> bool { super::iter_xhc().next().is_some() } +/// Initializes the host controller according to 4.2 of the xHCI specification. pub(crate) fn init() { - get_ownership_from_bios(); stop_and_reset(); set_num_of_enabled_slots(); + + dcbaa::init(); + scratchpad::init(); + exchanger::command::init(); + event::init(); + + run(); + ensure_no_error_occurs(); } pub(crate) fn run() { From d10ebe526495db5c49b859b7b7fbadfa40e79ca4 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 19:01:25 +0900 Subject: [PATCH 102/115] Docs --- test/src/xhc.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/src/xhc.rs b/test/src/xhc.rs index 25e8764e..420e8b36 100644 --- a/test/src/xhc.rs +++ b/test/src/xhc.rs @@ -112,7 +112,9 @@ fn wait_until_ready() { } fn set_num_of_enabled_slots() { - let n = num_of_device_slots(); + // We choose the maximum number of device slots for simplicity. + let n = num_of_max_device_slots(); + registers::handle(|r| { r.operational.config.update_volatile(|c| { c.set_max_device_slots_enabled(n); @@ -120,7 +122,7 @@ fn set_num_of_enabled_slots() { }) } -fn num_of_device_slots() -> u8 { +fn num_of_max_device_slots() -> u8 { registers::handle(|r| { r.capability .hcsparams1 From 6829f5374cba5c73fdda0cd1051fb46277bf9dbb Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 21:55:51 +0900 Subject: [PATCH 103/115] Page box --- test/src/exchanger/transfer.rs | 13 +- test/src/main.rs | 10 +- test/src/page_box.rs | 137 ++++++++++++++++++ test/src/port/class_driver/keyboard.rs | 5 +- .../src/port/class_driver/mass_storage/mod.rs | 45 +++--- test/src/port/class_driver/mouse.rs | 5 +- test/src/port/endpoint.rs | 7 +- test/src/port/init/descriptor_fetcher.rs | 9 +- test/src/port/init/fully_operational.rs | 5 +- test/src/structures/context.rs | 9 +- test/src/structures/dcbaa.rs | 7 +- test/src/structures/ring/command/mod.rs | 7 +- test/src/structures/ring/event/mod.rs | 13 +- .../structures/ring/event/segment_table.rs | 7 +- test/src/structures/ring/transfer/mod.rs | 7 +- test/src/structures/scratchpad.rs | 11 +- test/src/transition_helper.rs | 61 -------- 17 files changed, 206 insertions(+), 152 deletions(-) create mode 100644 test/src/page_box.rs delete mode 100644 test/src/transition_helper.rs diff --git a/test/src/exchanger/transfer.rs b/test/src/exchanger/transfer.rs index cc36b2d1..e16d3586 100644 --- a/test/src/exchanger/transfer.rs +++ b/test/src/exchanger/transfer.rs @@ -1,7 +1,6 @@ - use super::receiver::{self, ReceiveFuture}; +use crate::page_box::PageBox; use crate::structures::{descriptor, registers, ring::transfer}; -use crate::transition_helper::BoxWrapper; use alloc::{sync::Arc, vec::Vec}; use core::convert::TryInto; use futures_util::task::AtomicWaker; @@ -28,7 +27,7 @@ impl Sender { } pub(crate) async fn get_max_packet_size_from_device_descriptor(&mut self) -> u16 { - let b = BoxWrapper::from(descriptor::Device::default()); + let b = PageBox::from(descriptor::Device::default()); let setup = *transfer_trb::SetupStage::default() .set_transfer_type(TransferType::In) @@ -94,8 +93,8 @@ impl Sender { self.issue_trbs(&[setup.into(), status.into()]).await; } - pub(crate) async fn get_configuration_descriptor(&mut self) -> BoxWrapper<[u8]> { - let b = BoxWrapper::new_slice(0, 4096); + pub(crate) async fn get_configuration_descriptor(&mut self) -> PageBox<[u8]> { + let b = PageBox::new_slice(0, 4096); let (setup, data, status) = Self::trbs_for_getting_descriptors( &b, @@ -107,7 +106,7 @@ impl Sender { b } - pub(crate) async fn issue_normal_trb(&mut self, b: &BoxWrapper) { + pub(crate) async fn issue_normal_trb(&mut self, b: &PageBox) { let t = *Normal::default() .set_data_buffer_pointer(b.phys_addr().as_u64()) .set_trb_transfer_length(b.bytes().as_usize().try_into().unwrap()) @@ -117,7 +116,7 @@ impl Sender { } fn trbs_for_getting_descriptors( - b: &BoxWrapper, + b: &PageBox, t: DescTyIdx, ) -> ( transfer_trb::Allowed, diff --git a/test/src/main.rs b/test/src/main.rs index 51f27d29..31927c1f 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -10,12 +10,8 @@ use multitask::{executor::Executor, task::Task}; use pci::config::bar; use qemu_exit::QEMUExit; use qemu_print::qemu_println; -use spinning_top::{RawSpinlock, Spinlock}; -use structures::{ - dcbaa, extended_capabilities, registers, - ring::{command, event}, - scratchpad, -}; +use spinning_top::RawSpinlock; +use structures::{extended_capabilities, registers, ring::event}; use uefi::{ table::{boot::MemoryType, Boot, SystemTable}, Handle, @@ -30,10 +26,10 @@ mod exchanger; mod logger; mod mapper; mod multitask; +mod page_box; mod pci; mod port; mod structures; -mod transition_helper; mod xhc; #[uefi::entry] diff --git a/test/src/page_box.rs b/test/src/page_box.rs new file mode 100644 index 00000000..e1bd912a --- /dev/null +++ b/test/src/page_box.rs @@ -0,0 +1,137 @@ +use core::alloc::Layout; +use core::fmt; +use core::fmt::Debug; +use core::fmt::Formatter; +use core::marker::PhantomData; +use core::ops::Deref; +use core::ops::DerefMut; +use core::slice; +use os_units::Bytes; +use x86_64::PhysAddr; +use x86_64::VirtAddr; + +/// A `Box`-like type that locates the inner value at a 4K bytes page boundary. +/// +/// xHCI specification prohibits some structures to cross the page boundary. +/// Here, the size of a page is determined by Page Size Register (See 5.4.3 of +/// the spec). However, the minimum size of a page is 4K bytes, meaning that +/// keeping a structure within a 4K bytes page is always safe. It is very +/// costly, but at least it works. +pub struct PageBox { + addr: VirtAddr, + layout: Layout, + _marker: PhantomData, +} +impl PageBox { + pub fn phys_addr(&self) -> PhysAddr { + // We assume the identity mapping set up by UEFI firmware. + PhysAddr::new(self.addr.as_u64()) + } + + pub fn bytes(&self) -> Bytes { + Bytes::from(self.layout.size()) + } +} +impl PageBox<[T]> { + pub fn new_slice(init: T, len: usize) -> Self { + let bytes = Bytes::from(len * core::mem::size_of::()); + let align = 4096.max(core::mem::align_of::()); + + let layout = Layout::from_size_align(bytes.as_usize(), align); + let layout = layout.unwrap_or_else(|_| { + panic!( + "Failed to create a layout for {} bytes with {} bytes alignment", + bytes.as_usize(), + align + ) + }); + + // SAFETY: `Layout::from_size_align` guarantees that the layout is valid. + let addr = unsafe { alloc::alloc::alloc(layout) }; + + // SAFETY: Safe as the address is well-aligned. + unsafe { + let mut slice = slice::from_raw_parts_mut(addr as *mut T, len); + for i in 0..len { + slice[i] = init.clone(); + } + }; + + Self { + addr: VirtAddr::new(addr as u64), + layout, + _marker: PhantomData, + } + } +} +impl Deref for PageBox { + type Target = T; + fn deref(&self) -> &Self::Target { + // SAFETY: Safe as the address is well-aligned. + unsafe { &*self.addr.as_ptr() } + } +} +impl Deref for PageBox<[T]> { + type Target = [T]; + fn deref(&self) -> &Self::Target { + // SAFETY: Safe as the address is well-aligned and the memory is allocated. + unsafe { slice::from_raw_parts(self.addr.as_ptr(), self.bytes().as_usize()) } + } +} +impl DerefMut for PageBox { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: Safe as the address is well-aligned. + unsafe { &mut *self.addr.as_mut_ptr() } + } +} +impl DerefMut for PageBox<[T]> { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: Safe as the address is well-aligned and the memory is allocated. + unsafe { slice::from_raw_parts_mut(self.addr.as_mut_ptr(), self.bytes().as_usize()) } + } +} +impl From for PageBox { + fn from(inner: T) -> Self { + let bytes = Bytes::from(core::mem::size_of::()); + let align = 4096.max(core::mem::align_of::()); + + let layout = Layout::from_size_align(bytes.as_usize(), align); + let layout = layout.unwrap_or_else(|_| { + panic!( + "Failed to create a layout for {} bytes with {} bytes alignment", + bytes.as_usize(), + align + ) + }); + + // SAFETY: `Layout::from_size_align` guarantees that the layout is valid. + let addr = unsafe { alloc::alloc::alloc(layout) }; + + // SAFETY: Safe as the address is well-aligned. + unsafe { core::ptr::write(addr as *mut T, inner) }; + + Self { + addr: VirtAddr::new(addr as u64), + layout, + _marker: PhantomData, + } + } +} +impl Default for PageBox { + fn default() -> Self { + let x: T = Default::default(); + + Self::from(x) + } +} +impl Debug for PageBox { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.deref().fmt(f) + } +} +impl Drop for PageBox { + fn drop(&mut self) { + // SAFETY: `Layout::from_size_align` guarantees that the layout is valid. + unsafe { alloc::alloc::dealloc(self.addr.as_mut_ptr(), self.layout) } + } +} diff --git a/test/src/port/class_driver/keyboard.rs b/test/src/port/class_driver/keyboard.rs index c42c27d6..73e52b6b 100644 --- a/test/src/port/class_driver/keyboard.rs +++ b/test/src/port/class_driver/keyboard.rs @@ -1,8 +1,7 @@ - use crate::{ + page_box::PageBox, port::init::fully_operational::FullyOperational, structures::descriptor::{Configuration, Descriptor}, - transition_helper::BoxWrapper, }; use alloc::{string::String, vec::Vec}; use log::info; @@ -29,7 +28,7 @@ pub(in crate::port) async fn task(eps: FullyOperational) { pub(crate) struct Keyboard { ep: FullyOperational, - buf: BoxWrapper<[u8; 8]>, + buf: PageBox<[u8; 8]>, } impl Keyboard { pub(in crate::port) fn new(ep: FullyOperational) -> Self { diff --git a/test/src/port/class_driver/mass_storage/mod.rs b/test/src/port/class_driver/mass_storage/mod.rs index e7f36285..3ae8dbe2 100644 --- a/test/src/port/class_driver/mass_storage/mod.rs +++ b/test/src/port/class_driver/mass_storage/mod.rs @@ -1,10 +1,9 @@ - mod scsi; use crate::{ + page_box::PageBox, port::init::fully_operational::FullyOperational, structures::descriptor::{Configuration, Descriptor}, - transition_helper::BoxWrapper, }; use alloc::vec::Vec; use log::info; @@ -72,10 +71,9 @@ impl MassStorage { .build() .expect("Failed to build an inquiry command block wrapper."); let data = command_data_block::Inquiry::new(LEN); - let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + let mut wrapper = PageBox::from(CommandBlockWrapper::new(header, data.into())); - let (response, status): (BoxWrapper, _) = - self.send_scsi_command(&mut wrapper).await; + let (response, status): (PageBox, _) = self.send_scsi_command(&mut wrapper).await; status.check_corruption(); *response @@ -90,16 +88,16 @@ impl MassStorage { .build() .expect("Failed to build a read capacity command block wrapper"); let data = command_data_block::ReadCapacity::default(); - let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + let mut wrapper = PageBox::from(CommandBlockWrapper::new(header, data.into())); - let (response, status): (BoxWrapper, _) = + let (response, status): (PageBox, _) = self.send_scsi_command(&mut wrapper).await; status.check_corruption(); *response } - async fn read10(&mut self) -> BoxWrapper { + async fn read10(&mut self) -> PageBox { let header = CommandBlockWrapperHeaderBuilder::default() .transfer_length(0x8000) .flags(scsi::Flags::In) @@ -108,10 +106,9 @@ impl MassStorage { .build() .expect("Failed to build a read 10 command block wrapper."); let data = command_data_block::Read10::new(0, 64); - let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + let mut wrapper = PageBox::from(CommandBlockWrapper::new(header, data.into())); - let (response, status): (BoxWrapper, _) = - self.send_scsi_command(&mut wrapper).await; + let (response, status): (PageBox, _) = self.send_scsi_command(&mut wrapper).await; status.check_corruption(); response @@ -126,9 +123,9 @@ impl MassStorage { .build() .expect("Failed to build a write 10 command block wrapper."); let data = command_data_block::Write10::new(0, 64); - let mut wrapper = BoxWrapper::from(CommandBlockWrapper::new(header, data.into())); + let mut wrapper = PageBox::from(CommandBlockWrapper::new(header, data.into())); - let content = BoxWrapper::from(0x334_usize); + let content = PageBox::from(0x334_usize); let status = self.send_scsi_command_for_out(&mut wrapper, &content).await; status.check_corruption(); @@ -136,8 +133,8 @@ impl MassStorage { async fn send_scsi_command( &mut self, - c: &mut BoxWrapper, - ) -> (BoxWrapper, BoxWrapper) + c: &mut PageBox, + ) -> (PageBox, PageBox) where T: Default, { @@ -149,26 +146,26 @@ impl MassStorage { async fn send_scsi_command_for_out( &mut self, - c: &mut BoxWrapper, - d: &BoxWrapper, - ) -> BoxWrapper { + c: &mut PageBox, + d: &PageBox, + ) -> PageBox { self.send_command_block_wrapper(c).await; self.send_additional_data(d).await; self.receive_command_status().await } - async fn send_command_block_wrapper(&mut self, c: &mut BoxWrapper) { + async fn send_command_block_wrapper(&mut self, c: &mut PageBox) { self.ep .issue_normal_trb(c, EndpointType::BulkOut) .await .expect("Failed to send a SCSI command."); } - async fn receive_command_response(&mut self) -> BoxWrapper + async fn receive_command_response(&mut self) -> PageBox where T: Default, { - let c = BoxWrapper::default(); + let c = PageBox::default(); self.ep .issue_normal_trb(&c, EndpointType::BulkIn) .await @@ -176,15 +173,15 @@ impl MassStorage { c } - async fn send_additional_data(&mut self, d: &BoxWrapper) { + async fn send_additional_data(&mut self, d: &PageBox) { self.ep .issue_normal_trb(d, EndpointType::BulkOut) .await .expect("Failed to send a data."); } - async fn receive_command_status(&mut self) -> BoxWrapper { - let b = BoxWrapper::default(); + async fn receive_command_status(&mut self) -> PageBox { + let b = PageBox::default(); self.ep .issue_normal_trb(&b, EndpointType::BulkIn) .await diff --git a/test/src/port/class_driver/mouse.rs b/test/src/port/class_driver/mouse.rs index af10c901..62c3db4d 100644 --- a/test/src/port/class_driver/mouse.rs +++ b/test/src/port/class_driver/mouse.rs @@ -1,8 +1,7 @@ - use crate::{ + page_box::PageBox, port::init::fully_operational::FullyOperational, structures::descriptor::{Configuration, Descriptor}, - transition_helper::BoxWrapper, }; use alloc::vec::Vec; use log::info; @@ -28,7 +27,7 @@ pub(in super::super) async fn task(eps: FullyOperational) { pub(crate) struct Mouse { ep: FullyOperational, - buf: BoxWrapper<[i8; 4]>, + buf: PageBox<[i8; 4]>, } impl Mouse { pub(super) fn new(ep: FullyOperational) -> Self { diff --git a/test/src/port/endpoint.rs b/test/src/port/endpoint.rs index 28471186..a5239c17 100644 --- a/test/src/port/endpoint.rs +++ b/test/src/port/endpoint.rs @@ -1,5 +1,4 @@ - -use crate::{exchanger::transfer, structures::descriptor, transition_helper::BoxWrapper}; +use crate::{exchanger::transfer, page_box::PageBox, structures::descriptor}; use x86_64::PhysAddr; use xhci::context::EndpointType; @@ -21,7 +20,7 @@ impl Default { .await } - pub(super) async fn get_raw_configuration_descriptors(&mut self) -> BoxWrapper<[u8]> { + pub(super) async fn get_raw_configuration_descriptors(&mut self) -> PageBox<[u8]> { self.sender.get_configuration_descriptor().await } @@ -59,7 +58,7 @@ impl NonDefault { self.desc.ty() } - pub(super) async fn issue_normal_trb(&mut self, b: &BoxWrapper) { + pub(super) async fn issue_normal_trb(&mut self, b: &PageBox) { self.sender.issue_normal_trb(b).await } } diff --git a/test/src/port/init/descriptor_fetcher.rs b/test/src/port/init/descriptor_fetcher.rs index bd33d8ec..95c01b89 100644 --- a/test/src/port/init/descriptor_fetcher.rs +++ b/test/src/port/init/descriptor_fetcher.rs @@ -1,11 +1,10 @@ - use super::{ endpoints_initializer::EndpointsInitializer, max_packet_size_setter::MaxPacketSizeSetter, }; use crate::{ + page_box::PageBox, port::endpoint, structures::{context::Context, descriptor, descriptor::Descriptor}, - transition_helper::BoxWrapper, }; use alloc::{sync::Arc, vec::Vec}; use log::debug; @@ -54,18 +53,18 @@ impl DescriptorFetcher { self.ep0 } - async fn get_raw_descriptors(&mut self) -> BoxWrapper<[u8]> { + async fn get_raw_descriptors(&mut self) -> PageBox<[u8]> { self.ep0.get_raw_configuration_descriptors().await } } struct RawDescriptorParser { - raw: BoxWrapper<[u8]>, + raw: PageBox<[u8]>, current: usize, len: usize, } impl RawDescriptorParser { - fn new(raw: BoxWrapper<[u8]>) -> Self { + fn new(raw: PageBox<[u8]>) -> Self { let len = raw.len(); Self { diff --git a/test/src/port/init/fully_operational.rs b/test/src/port/init/fully_operational.rs index 1f92aaef..9ba955a8 100644 --- a/test/src/port/init/fully_operational.rs +++ b/test/src/port/init/fully_operational.rs @@ -1,12 +1,11 @@ - use super::endpoints_initializer::EndpointsInitializer; use crate::{ + page_box::PageBox, port::{ endpoint, endpoint::{Error, NonDefault}, }, structures::descriptor::Descriptor, - transition_helper::BoxWrapper, }; use alloc::vec::Vec; use core::slice; @@ -44,7 +43,7 @@ impl FullyOperational { pub(in super::super) async fn issue_normal_trb( &mut self, - b: &BoxWrapper, + b: &PageBox, ty: EndpointType, ) -> Result<(), Error> { for ep in &mut self.eps { diff --git a/test/src/structures/context.rs b/test/src/structures/context.rs index f6f0b59e..4b30a706 100644 --- a/test/src/structures/context.rs +++ b/test/src/structures/context.rs @@ -1,5 +1,4 @@ - -use crate::transition_helper::BoxWrapper; +use crate::page_box::PageBox; use super::registers; use alloc::boxed::Box; @@ -11,7 +10,7 @@ use xhci::context::{ pub(crate) struct Context { pub(crate) input: Input, - pub(crate) output: BoxWrapper, + pub(crate) output: PageBox, } impl Default for Context { fn default() -> Self { @@ -23,8 +22,8 @@ impl Default for Context { } pub(crate) enum Input { - Byte64(BoxWrapper), - Byte32(BoxWrapper), + Byte64(PageBox), + Byte32(PageBox), } impl Input { pub(crate) fn control_mut(&mut self) -> &mut dyn InputControlHandler { diff --git a/test/src/structures/dcbaa.rs b/test/src/structures/dcbaa.rs index efbd505a..8196fcfa 100644 --- a/test/src/structures/dcbaa.rs +++ b/test/src/structures/dcbaa.rs @@ -1,5 +1,4 @@ - -use crate::transition_helper::BoxWrapper; +use crate::page_box::PageBox; use super::registers; use conquer_once::spin::Lazy; @@ -19,11 +18,11 @@ pub(crate) fn register(port_id: usize, a: PhysAddr) { } pub(crate) struct DeviceContextBaseAddressArray { - arr: BoxWrapper<[PhysAddr]>, + arr: PageBox<[PhysAddr]>, } impl DeviceContextBaseAddressArray { fn new() -> Self { - let arr = BoxWrapper::new_slice(PhysAddr::zero(), Self::num_of_slots()); + let arr = PageBox::new_slice(PhysAddr::zero(), Self::num_of_slots()); Self { arr } } diff --git a/test/src/structures/ring/command/mod.rs b/test/src/structures/ring/command/mod.rs index 9d736bf9..ee2c2e77 100644 --- a/test/src/structures/ring/command/mod.rs +++ b/test/src/structures/ring/command/mod.rs @@ -1,6 +1,5 @@ - use super::CycleBit; -use crate::{registers, transition_helper::BoxWrapper}; +use crate::{page_box::PageBox, registers}; use trb::Link; use x86_64::{ structures::paging::{PageSize, Size4KiB}, @@ -48,14 +47,14 @@ impl Default for Ring { } struct Raw { - raw: BoxWrapper<[[u32; 4]]>, + raw: PageBox<[[u32; 4]]>, enq_p: usize, c: CycleBit, } impl Raw { fn new() -> Self { Self { - raw: BoxWrapper::new_slice([0; 4], NUM_OF_TRBS), + raw: PageBox::new_slice([0; 4], NUM_OF_TRBS), enq_p: 0, c: CycleBit::new(true), } diff --git a/test/src/structures/ring/event/mod.rs b/test/src/structures/ring/event/mod.rs index 6118e7ae..9faf658d 100644 --- a/test/src/structures/ring/event/mod.rs +++ b/test/src/structures/ring/event/mod.rs @@ -1,5 +1,5 @@ use super::CycleBit; -use crate::{exchanger::receiver, port, structures::registers, transition_helper::BoxWrapper}; +use crate::{exchanger::receiver, page_box::PageBox, port, structures::registers}; use alloc::vec::Vec; use bit_field::BitField; use conquer_once::spin::OnceCell; @@ -115,7 +115,7 @@ impl Stream for Ring { } struct Raw { - rings: Vec>, + rings: Vec>, c: CycleBit, deq_p_seg: usize, deq_p_trb: usize, @@ -131,13 +131,10 @@ impl Raw { } } - fn new_rings() -> Vec> { + fn new_rings() -> Vec> { let mut v = Vec::new(); for _ in 0..Self::max_num_of_erst() { - v.push(BoxWrapper::new_slice( - [0; 4], - MAX_NUM_OF_TRB_IN_QUEUE.into(), - )); + v.push(PageBox::new_slice([0; 4], MAX_NUM_OF_TRB_IN_QUEUE.into())); } v @@ -219,7 +216,7 @@ impl Raw { } fn head_addrs(&self) -> Vec { - self.rings.iter().map(BoxWrapper::phys_addr).collect() + self.rings.iter().map(PageBox::phys_addr).collect() } } diff --git a/test/src/structures/ring/event/segment_table.rs b/test/src/structures/ring/event/segment_table.rs index 9140d5b7..dfe7e01e 100644 --- a/test/src/structures/ring/event/segment_table.rs +++ b/test/src/structures/ring/event/segment_table.rs @@ -1,17 +1,16 @@ - use core::{ ops::{Index, IndexMut}, slice, }; use x86_64::PhysAddr; -use crate::transition_helper::BoxWrapper; +use crate::page_box::PageBox; #[derive(Debug)] -pub struct SegmentTable(BoxWrapper<[Entry]>); +pub struct SegmentTable(PageBox<[Entry]>); impl SegmentTable { pub fn new(len: usize) -> Self { - Self(BoxWrapper::new_slice(Entry::null(), len)) + Self(PageBox::new_slice(Entry::null(), len)) } pub fn phys_addr(&self) -> PhysAddr { diff --git a/test/src/structures/ring/transfer/mod.rs b/test/src/structures/ring/transfer/mod.rs index bdc24079..4c90bb0e 100644 --- a/test/src/structures/ring/transfer/mod.rs +++ b/test/src/structures/ring/transfer/mod.rs @@ -1,6 +1,5 @@ - use super::CycleBit; -use crate::transition_helper::BoxWrapper; +use crate::page_box::PageBox; use alloc::vec::Vec; use trb::Link; use x86_64::PhysAddr; @@ -26,14 +25,14 @@ impl Ring { } struct Raw { - ring: BoxWrapper<[[u32; 4]]>, + ring: PageBox<[[u32; 4]]>, enq_p: usize, c: CycleBit, } impl Raw { fn new() -> Self { Self { - ring: BoxWrapper::new_slice([0; 4], SIZE_OF_RING), + ring: PageBox::new_slice([0; 4], SIZE_OF_RING), enq_p: 0, c: CycleBit::new(true), } diff --git a/test/src/structures/scratchpad.rs b/test/src/structures/scratchpad.rs index a72200da..769cfefa 100644 --- a/test/src/structures/scratchpad.rs +++ b/test/src/structures/scratchpad.rs @@ -1,7 +1,6 @@ - use super::dcbaa; +use crate::page_box::PageBox; use crate::registers; -use crate::transition_helper::BoxWrapper; use alloc::vec::Vec; use conquer_once::spin::OnceCell; use core::convert::TryInto; @@ -25,15 +24,15 @@ fn init_static() { } struct Scratchpad { - arr: BoxWrapper<[PhysAddr]>, - bufs: Vec>, + arr: PageBox<[PhysAddr]>, + bufs: Vec>, } impl Scratchpad { fn new() -> Self { let len: usize = Self::num_of_buffers().try_into().unwrap(); Self { - arr: BoxWrapper::new_slice(PhysAddr::zero(), len), + arr: PageBox::new_slice(PhysAddr::zero(), len), bufs: Vec::new(), } } @@ -55,7 +54,7 @@ impl Scratchpad { for _ in 0..Self::num_of_buffers() { // Allocate the double size of memory, then register the aligned address with the // array. - let b = BoxWrapper::new_slice(0, Self::page_size().as_usize() * 2); + let b = PageBox::new_slice(0, Self::page_size().as_usize() * 2); self.bufs.push(b); } } diff --git a/test/src/transition_helper.rs b/test/src/transition_helper.rs deleted file mode 100644 index f4ed5a5c..00000000 --- a/test/src/transition_helper.rs +++ /dev/null @@ -1,61 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec; -use core::fmt; -use core::fmt::Debug; -use core::fmt::Formatter; -use core::ops::Deref; -use core::ops::DerefMut; -use os_units::Bytes; -use x86_64::PhysAddr; - -pub struct BoxWrapper { - inner: Box, - bytes: u64, -} -impl BoxWrapper { - pub fn new(inner: Box, bytes: u64) -> Self { - Self { inner, bytes } - } - - pub fn phys_addr(&self) -> PhysAddr { - PhysAddr::new(self.inner.as_ref() as *const T as *const u8 as u64) - } - - pub fn bytes(&self) -> Bytes { - Bytes::new(self.bytes as _) - } -} -impl BoxWrapper<[T]> { - pub fn new_slice(init: T, len: usize) -> Self { - Self::new( - vec![init; len].into_boxed_slice(), - (len * core::mem::size_of::()) as u64, - ) - } -} -impl Deref for BoxWrapper { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.inner - } -} -impl DerefMut for BoxWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} -impl From for BoxWrapper { - fn from(inner: T) -> Self { - Self::new(Box::new(inner), core::mem::size_of::() as u64) - } -} -impl Default for BoxWrapper { - fn default() -> Self { - Self::new(Box::new(T::default()), core::mem::size_of::() as u64) - } -} -impl Debug for BoxWrapper { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} From e970dd92826fb65a95c316e016dac21c6e088dea Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 21:56:35 +0900 Subject: [PATCH 104/115] Fix --- test/src/page_box.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/src/page_box.rs b/test/src/page_box.rs index e1bd912a..bfca698d 100644 --- a/test/src/page_box.rs +++ b/test/src/page_box.rs @@ -12,10 +12,10 @@ use x86_64::VirtAddr; /// A `Box`-like type that locates the inner value at a 4K bytes page boundary. /// -/// xHCI specification prohibits some structures to cross the page boundary. -/// Here, the size of a page is determined by Page Size Register (See 5.4.3 of -/// the spec). However, the minimum size of a page is 4K bytes, meaning that -/// keeping a structure within a 4K bytes page is always safe. It is very +/// xHCI specification prohibits some structures from crossing the page +/// boundary. Here, the size of a page is determined by Page Size Register (See +/// 5.4.3 of the spec). However, the minimum size of a page is 4K bytes, meaning +/// that keeping a structure within a 4K bytes page is always safe. It is very /// costly, but at least it works. pub struct PageBox { addr: VirtAddr, From 82b4f8ef5e69271a02248c75ce4624c67fd37a1d Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 22:56:49 +0900 Subject: [PATCH 105/115] DCBAA --- .../port/init/slot_structures_initializer.rs | 3 +- test/src/structures/dcbaa.rs | 86 +++++++------------ test/src/structures/scratchpad.rs | 2 +- 3 files changed, 35 insertions(+), 56 deletions(-) diff --git a/test/src/port/init/slot_structures_initializer.rs b/test/src/port/init/slot_structures_initializer.rs index 33a8c84e..a3a6ec64 100644 --- a/test/src/port/init/slot_structures_initializer.rs +++ b/test/src/port/init/slot_structures_initializer.rs @@ -1,4 +1,3 @@ - use super::{max_packet_size_setter::MaxPacketSizeSetter, resetter::Resetter}; use crate::{ exchanger, @@ -65,7 +64,7 @@ impl SlotStructuresInitializer { fn register_with_dcbaa(&self) { let a = self.cx.lock().output.phys_addr(); - dcbaa::register(self.slot_number.into(), a); + dcbaa::register_device_context_addr(self.slot_number.into(), a); } async fn issue_address_device(&self) { diff --git a/test/src/structures/dcbaa.rs b/test/src/structures/dcbaa.rs index 8196fcfa..6565950e 100644 --- a/test/src/structures/dcbaa.rs +++ b/test/src/structures/dcbaa.rs @@ -1,68 +1,48 @@ use crate::page_box::PageBox; use super::registers; -use conquer_once::spin::Lazy; -use core::ops::{Index, IndexMut}; +use conquer_once::spin::OnceCell; +use core::ops::DerefMut; use spinning_top::Spinlock; use x86_64::PhysAddr; -static DCBAA: Lazy> = - Lazy::new(|| Spinlock::new(DeviceContextBaseAddressArray::new())); +static DCBAA: OnceCell>> = OnceCell::uninit(); -pub(crate) fn init() { - DCBAA.lock().init(); -} - -pub(crate) fn register(port_id: usize, a: PhysAddr) { - DCBAA.lock()[port_id] = a; -} +pub fn init() { + DCBAA.init_once(|| Spinlock::new(PageBox::new_slice(PhysAddr::zero(), array_len()))); -pub(crate) struct DeviceContextBaseAddressArray { - arr: PageBox<[PhysAddr]>, + registers::handle(|r| { + r.operational.dcbaap.update_volatile(|d| { + d.set(lock().phys_addr().as_u64()); + }) + }) } -impl DeviceContextBaseAddressArray { - fn new() -> Self { - let arr = PageBox::new_slice(PhysAddr::zero(), Self::num_of_slots()); - Self { arr } - } - - fn init(&self) { - self.register_address_to_xhci_register(); - } - fn num_of_slots() -> usize { - registers::handle(|r| { - r.capability - .hcsparams1 - .read_volatile() - .number_of_device_slots() - + 1 - }) - .into() - } +pub fn register_device_context_addr(port_id: usize, a: PhysAddr) { + assert_ne!(port_id, 0, "A port ID must be greater than 0."); - fn register_address_to_xhci_register(&self) { - registers::handle(|r| { - let _ = &self; - r.operational.dcbaap.update_volatile(|d| { - let _ = &self; - d.set(self.phys_addr().as_u64()); - }) - }) - } + lock()[port_id] = a; +} - fn phys_addr(&self) -> PhysAddr { - self.arr.phys_addr() - } +pub fn register_scratchpad_addr(a: PhysAddr) { + lock()[0] = a; } -impl Index for DeviceContextBaseAddressArray { - type Output = PhysAddr; - fn index(&self, index: usize) -> &Self::Output { - &self.arr[index] - } + +fn lock() -> impl DerefMut> { + DCBAA + .try_get() + .expect("`DCBAA` is not initialized.") + .try_lock() + .expect("Failed to lock `DCBAA`.") } -impl IndexMut for DeviceContextBaseAddressArray { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.arr[index] - } + +fn array_len() -> usize { + registers::handle(|r| { + r.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() + + 1 + }) + .into() } diff --git a/test/src/structures/scratchpad.rs b/test/src/structures/scratchpad.rs index 769cfefa..5b4c8c36 100644 --- a/test/src/structures/scratchpad.rs +++ b/test/src/structures/scratchpad.rs @@ -47,7 +47,7 @@ impl Scratchpad { } fn register_with_dcbaa(&self) { - dcbaa::register(0, self.arr.phys_addr()); + dcbaa::register_device_context_addr(0, self.arr.phys_addr()); } fn allocate_buffers(&mut self) { From e0839b8288be60f840900c8d5b0e75d173f6c3a3 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 22:59:21 +0900 Subject: [PATCH 106/115] Rename --- test/src/structures/scratchpad.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/structures/scratchpad.rs b/test/src/structures/scratchpad.rs index 5b4c8c36..4c061c7d 100644 --- a/test/src/structures/scratchpad.rs +++ b/test/src/structures/scratchpad.rs @@ -10,7 +10,7 @@ use x86_64::PhysAddr; static SCRATCHPAD: OnceCell = OnceCell::uninit(); pub(crate) fn init() { - if Scratchpad::exists() { + if Scratchpad::needed() { init_static(); } } @@ -37,7 +37,7 @@ impl Scratchpad { } } - fn exists() -> bool { + fn needed() -> bool { Self::num_of_buffers() > 0 } From 61fdd2586091f4832ca028f0c2726bac3d47b16b Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:07:34 +0900 Subject: [PATCH 107/115] Scratchpad --- test/src/page_box.rs | 18 ++++++++++++++++++ test/src/structures/scratchpad.rs | 16 +++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/test/src/page_box.rs b/test/src/page_box.rs index bfca698d..1096ca4a 100644 --- a/test/src/page_box.rs +++ b/test/src/page_box.rs @@ -23,6 +23,24 @@ pub struct PageBox { _marker: PhantomData, } impl PageBox { + pub fn from_layout_zeroed(layout: Layout) -> Self { + assert!( + layout.size() > 0, + "The size of the layout must be greater than 0." + ); + + let addr = unsafe { alloc::alloc::alloc(layout) }; + + // SAFETY: Safe as the address is well-aligned. + unsafe { core::ptr::write_bytes(addr as *mut u8, 0, layout.size()) }; + + Self { + addr: VirtAddr::new(addr as u64), + layout, + _marker: PhantomData, + } + } + pub fn phys_addr(&self) -> PhysAddr { // We assume the identity mapping set up by UEFI firmware. PhysAddr::new(self.addr.as_u64()) diff --git a/test/src/structures/scratchpad.rs b/test/src/structures/scratchpad.rs index 4c061c7d..c2f93a36 100644 --- a/test/src/structures/scratchpad.rs +++ b/test/src/structures/scratchpad.rs @@ -3,6 +3,7 @@ use crate::page_box::PageBox; use crate::registers; use alloc::vec::Vec; use conquer_once::spin::OnceCell; +use core::alloc::Layout; use core::convert::TryInto; use os_units::Bytes; use x86_64::PhysAddr; @@ -51,10 +52,19 @@ impl Scratchpad { } fn allocate_buffers(&mut self) { + let layout = + Layout::from_size_align(Self::page_size().as_usize(), Self::page_size().as_usize()); + let layout = layout.unwrap_or_else(|_| { + panic!( + "Failed to create a layout for {} bytes with {} bytes alignment", + Self::page_size().as_usize(), + Self::page_size().as_usize() + ) + }); + for _ in 0..Self::num_of_buffers() { - // Allocate the double size of memory, then register the aligned address with the - // array. - let b = PageBox::new_slice(0, Self::page_size().as_usize() * 2); + let b = PageBox::from_layout_zeroed(layout); + self.bufs.push(b); } } From a8fcc4992930d9c6fe1bbf443774af46503f9514 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:12:25 +0900 Subject: [PATCH 108/115] ? --- test/src/structures/ring/command/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/src/structures/ring/command/mod.rs b/test/src/structures/ring/command/mod.rs index ee2c2e77..efd9d4f4 100644 --- a/test/src/structures/ring/command/mod.rs +++ b/test/src/structures/ring/command/mod.rs @@ -69,8 +69,6 @@ impl Raw { } fn write_trb(&mut self, trb: command::Allowed) { - // TODO: Write four 32-bit values. This way of writing is described in the spec, although - // I cannot find which section has the description. self.raw[self.enq_p] = trb.into_raw(); } From 4024e6d2511dbdc27048c493d0caca8b5578eac3 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:22:26 +0900 Subject: [PATCH 109/115] Fix the len --- test/src/page_box.rs | 8 ++++++-- test/src/structures/ring/event/mod.rs | 3 +++ test/src/structures/ring/event/segment_table.rs | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/src/page_box.rs b/test/src/page_box.rs index 1096ca4a..451f7d9e 100644 --- a/test/src/page_box.rs +++ b/test/src/page_box.rs @@ -92,8 +92,10 @@ impl Deref for PageBox { impl Deref for PageBox<[T]> { type Target = [T]; fn deref(&self) -> &Self::Target { + let len = self.bytes().as_usize() / core::mem::size_of::(); + // SAFETY: Safe as the address is well-aligned and the memory is allocated. - unsafe { slice::from_raw_parts(self.addr.as_ptr(), self.bytes().as_usize()) } + unsafe { slice::from_raw_parts(self.addr.as_ptr(), len) } } } impl DerefMut for PageBox { @@ -104,8 +106,10 @@ impl DerefMut for PageBox { } impl DerefMut for PageBox<[T]> { fn deref_mut(&mut self) -> &mut Self::Target { + let len = self.bytes().as_usize() / core::mem::size_of::(); + // SAFETY: Safe as the address is well-aligned and the memory is allocated. - unsafe { slice::from_raw_parts_mut(self.addr.as_mut_ptr(), self.bytes().as_usize()) } + unsafe { slice::from_raw_parts_mut(self.addr.as_mut_ptr(), len) } } } impl From for PageBox { diff --git a/test/src/structures/ring/event/mod.rs b/test/src/structures/ring/event/mod.rs index 9faf658d..5c41be28 100644 --- a/test/src/structures/ring/event/mod.rs +++ b/test/src/structures/ring/event/mod.rs @@ -10,6 +10,7 @@ use core::{ }; use futures_util::{stream::Stream, StreamExt}; use log::{debug, info, warn}; +use qemu_print::qemu_println; use segment_table::SegmentTable; use spinning_top::Spinlock; use x86_64::{ @@ -242,6 +243,8 @@ impl<'a> SegTblInitializer<'a> { } fn register_tbl_sz(&mut self) { + qemu_println!("tbl_len: {}", self.tbl_len()); + registers::handle(|r| { let l = self.tbl_len(); diff --git a/test/src/structures/ring/event/segment_table.rs b/test/src/structures/ring/event/segment_table.rs index dfe7e01e..dfae168a 100644 --- a/test/src/structures/ring/event/segment_table.rs +++ b/test/src/structures/ring/event/segment_table.rs @@ -2,6 +2,7 @@ use core::{ ops::{Index, IndexMut}, slice, }; +use qemu_print::qemu_println; use x86_64::PhysAddr; use crate::page_box::PageBox; @@ -10,6 +11,7 @@ use crate::page_box::PageBox; pub struct SegmentTable(PageBox<[Entry]>); impl SegmentTable { pub fn new(len: usize) -> Self { + qemu_println!("SegmentTable::new({})", len); Self(PageBox::new_slice(Entry::null(), len)) } From 5519b622f2cbc1e5ef03c0d494bc907fa3aa858c Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:25:06 +0900 Subject: [PATCH 110/115] Fix --- test/src/structures/ring/event/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/src/structures/ring/event/mod.rs b/test/src/structures/ring/event/mod.rs index 5c41be28..bfc0f97d 100644 --- a/test/src/structures/ring/event/mod.rs +++ b/test/src/structures/ring/event/mod.rs @@ -243,8 +243,6 @@ impl<'a> SegTblInitializer<'a> { } fn register_tbl_sz(&mut self) { - qemu_println!("tbl_len: {}", self.tbl_len()); - registers::handle(|r| { let l = self.tbl_len(); From f2745850fac072edd74877bbcc04fef6cfefb096 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:30:33 +0900 Subject: [PATCH 111/115] Use `BTreeSet` --- test/src/port/spawner.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/src/port/spawner.rs b/test/src/port/spawner.rs index 416e5ef4..23c579f0 100644 --- a/test/src/port/spawner.rs +++ b/test/src/port/spawner.rs @@ -1,12 +1,9 @@ - use crate::multitask; -use alloc::{vec, vec::Vec}; -use conquer_once::spin::Lazy; +use alloc::collections::BTreeSet; use multitask::task::Task; use spinning_top::Spinlock; -static SPAWN_STATUS: Lazy>> = - Lazy::new(|| Spinlock::new(vec![false; super::max_num().into()])); +static SPAWN_STATUS: Spinlock> = Spinlock::new(BTreeSet::new()); pub(crate) fn spawn_all_connected_ports() { let n = super::max_num(); @@ -38,11 +35,11 @@ fn spawnable(p: u8) -> bool { } fn spawned(p: u8) -> bool { - SPAWN_STATUS.lock()[usize::from(p)] + SPAWN_STATUS.lock().contains(&p.into()) } fn mark_as_spawned(p: u8) { - SPAWN_STATUS.lock()[usize::from(p)] = true; + SPAWN_STATUS.lock().insert(p.into()); } #[derive(Debug)] From 11afe3a0af9bdf23abaa2eb70c3e7f96ee762e55 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:47:13 +0900 Subject: [PATCH 112/115] Noop --- test/src/exchanger/transfer.rs | 8 +++++++- test/src/port/endpoint.rs | 4 ++++ test/src/port/init/fully_operational.rs | 4 ++++ test/src/port/mod.rs | 21 +++++---------------- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/test/src/exchanger/transfer.rs b/test/src/exchanger/transfer.rs index e16d3586..73ebc9fe 100644 --- a/test/src/exchanger/transfer.rs +++ b/test/src/exchanger/transfer.rs @@ -9,7 +9,7 @@ use spinning_top::Spinlock; use x86_64::PhysAddr; use xhci::ring::trb::{ event, transfer as transfer_trb, - transfer::{Direction, Normal, TransferType}, + transfer::{Direction, Noop, Normal, TransferType}, }; pub(crate) struct Sender { @@ -115,6 +115,12 @@ impl Sender { self.issue_trbs(&[t.into()]).await; } + pub(crate) async fn issue_nop_trb(&mut self) { + let t = Noop::default(); + + self.issue_trbs(&[t.into()]).await; + } + fn trbs_for_getting_descriptors( b: &PageBox, t: DescTyIdx, diff --git a/test/src/port/endpoint.rs b/test/src/port/endpoint.rs index a5239c17..59ff688a 100644 --- a/test/src/port/endpoint.rs +++ b/test/src/port/endpoint.rs @@ -35,6 +35,10 @@ impl Default { pub(super) async fn set_boot_protocol(&mut self) { self.sender.set_boot_protocol().await; } + + pub(super) async fn issue_nop_trb(&mut self) { + self.sender.issue_nop_trb().await; + } } pub(super) struct NonDefault { diff --git a/test/src/port/init/fully_operational.rs b/test/src/port/init/fully_operational.rs index 9ba955a8..23260db2 100644 --- a/test/src/port/init/fully_operational.rs +++ b/test/src/port/init/fully_operational.rs @@ -56,6 +56,10 @@ impl FullyOperational { Err(Error::NoSuchEndpoint(ty)) } + pub(in super::super) async fn issue_nop_trb(&mut self) { + self.def_ep.issue_nop_trb().await; + } + pub(in super::super) async fn set_configure(&mut self, config_val: u8) { self.def_ep.set_configuration(config_val).await; } diff --git a/test/src/port/mod.rs b/test/src/port/mod.rs index 61c94bde..0f9506cd 100644 --- a/test/src/port/mod.rs +++ b/test/src/port/mod.rs @@ -1,4 +1,3 @@ - use super::structures::registers; use crate::multitask::{self, task::Task}; use alloc::collections::VecDeque; @@ -7,6 +6,7 @@ use core::{future::Future, pin::Pin, task::Poll}; use futures_util::task::AtomicWaker; use init::fully_operational::FullyOperational; use log::{info, warn}; +use qemu_print::qemu_println; use spinning_top::Spinlock; mod class_driver; @@ -52,22 +52,11 @@ pub(crate) fn try_spawn(port_idx: u8) -> Result<(), spawner::PortNotConnected> { } async fn main(port_number: u8) { - let fully_operational = init_port_and_slot_exclusively(port_number).await; + let mut fully_operational = init_port_and_slot_exclusively(port_number).await; - match fully_operational.ty() { - (3, 1, 2) => { - multitask::add(Task::new_poll(class_driver::mouse::task(fully_operational))); - } - (3, 1, 1) => { - multitask::add(Task::new_poll(class_driver::keyboard::task( - fully_operational, - ))); - } - (8, _, _) => multitask::add(Task::new(class_driver::mass_storage::task( - fully_operational, - ))), - t => warn!("Unknown device: {:?}", t), - } + fully_operational.issue_nop_trb().await; + + qemu_println!("Port {} is fully operational.", port_number); } async fn init_port_and_slot_exclusively(port_number: u8) -> FullyOperational { From af312fb2832ce0735f44cb079b23d8c69195ccc9 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:52:26 +0900 Subject: [PATCH 113/115] success --- test/src/exchanger/receiver.rs | 1 - test/src/structures/ring/event/mod.rs | 14 ++++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/test/src/exchanger/receiver.rs b/test/src/exchanger/receiver.rs index 32d7357d..6b1283a3 100644 --- a/test/src/exchanger/receiver.rs +++ b/test/src/exchanger/receiver.rs @@ -1,4 +1,3 @@ - use alloc::{collections::BTreeMap, sync::Arc}; use conquer_once::spin::Lazy; use core::{ diff --git a/test/src/structures/ring/event/mod.rs b/test/src/structures/ring/event/mod.rs index bfc0f97d..eb2c6dbd 100644 --- a/test/src/structures/ring/event/mod.rs +++ b/test/src/structures/ring/event/mod.rs @@ -17,7 +17,10 @@ use x86_64::{ structures::paging::{PageSize, Size4KiB}, PhysAddr, }; -use xhci::ring::{trb, trb::event}; +use xhci::ring::{ + trb, + trb::event::{self, CompletionCode}, +}; mod segment_table; @@ -43,10 +46,13 @@ pub(crate) async fn task() { .next() .await { - info!("TRB: {:?}", trb); - if let event::Allowed::CommandCompletion(_) = trb { + if let event::Allowed::CommandCompletion(x) = trb { + assert_eq!(x.completion_code(), Ok(CompletionCode::Success)); + receiver::receive(trb); - } else if let event::Allowed::TransferEvent(_) = trb { + } else if let event::Allowed::TransferEvent(x) = trb { + assert_eq!(x.completion_code(), Ok(CompletionCode::Success)); + receiver::receive(trb); } else if let event::Allowed::PortStatusChange(p) = trb { let _ = port::try_spawn(p.port_id()); From 1c0c660e4eb25c55e816e49f227982a95bfd6455 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 19 Dec 2023 23:57:01 +0900 Subject: [PATCH 114/115] Exit --- test/src/port/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/src/port/mod.rs b/test/src/port/mod.rs index 0f9506cd..b48538d7 100644 --- a/test/src/port/mod.rs +++ b/test/src/port/mod.rs @@ -6,8 +6,10 @@ use core::{future::Future, pin::Pin, task::Poll}; use futures_util::task::AtomicWaker; use init::fully_operational::FullyOperational; use log::{info, warn}; +use qemu_exit::{QEMUExit, X86}; use qemu_print::qemu_println; use spinning_top::Spinlock; +use uefi::table::cfg::HAND_OFF_BLOCK_LIST_GUID; mod class_driver; mod endpoint; @@ -52,11 +54,17 @@ pub(crate) fn try_spawn(port_idx: u8) -> Result<(), spawner::PortNotConnected> { } async fn main(port_number: u8) { + qemu_println!("Port {} is connected.", port_number); + let mut fully_operational = init_port_and_slot_exclusively(port_number).await; fully_operational.issue_nop_trb().await; qemu_println!("Port {} is fully operational.", port_number); + + let exit_handler = X86::new(0xf4, 33); + + exit_handler.exit_success(); } async fn init_port_and_slot_exclusively(port_number: u8) -> FullyOperational { From 37bb4b8039fc2e0c55a032e06f89f8ebae9beafd Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Wed, 20 Dec 2023 09:49:22 +0900 Subject: [PATCH 115/115] Format --- test/src/exchanger/mod.rs | 1 - test/src/pci/config/bar.rs | 1 - test/src/pci/config/common.rs | 1 - test/src/pci/config/mod.rs | 1 - test/src/pci/config/type_spec/mod.rs | 1 - test/src/pci/config/type_spec/non_bridge.rs | 1 - test/src/pci/mod.rs | 1 - .../port/class_driver/mass_storage/scsi/command_data_block.rs | 1 - test/src/port/class_driver/mass_storage/scsi/mod.rs | 1 - test/src/port/class_driver/mass_storage/scsi/response.rs | 1 - test/src/port/class_driver/mod.rs | 1 - test/src/port/init/endpoints_initializer.rs | 1 - test/src/port/init/max_packet_size_setter.rs | 1 - test/src/port/init/mod.rs | 1 - test/src/port/init/resetter.rs | 1 - test/src/structures/descriptor.rs | 1 - test/src/structures/mod.rs | 1 - test/src/structures/ring/mod.rs | 1 - 18 files changed, 18 deletions(-) diff --git a/test/src/exchanger/mod.rs b/test/src/exchanger/mod.rs index 901df1a5..db6d4e16 100644 --- a/test/src/exchanger/mod.rs +++ b/test/src/exchanger/mod.rs @@ -1,4 +1,3 @@ - pub(crate) mod command; pub(crate) mod receiver; pub(crate) mod transfer; diff --git a/test/src/pci/config/bar.rs b/test/src/pci/config/bar.rs index b8a8dc7b..30952770 100644 --- a/test/src/pci/config/bar.rs +++ b/test/src/pci/config/bar.rs @@ -1,4 +1,3 @@ - use super::RegisterIndex; use core::{ convert::{From, TryFrom}, diff --git a/test/src/pci/config/common.rs b/test/src/pci/config/common.rs index b91fb93d..57824423 100644 --- a/test/src/pci/config/common.rs +++ b/test/src/pci/config/common.rs @@ -1,4 +1,3 @@ - use super::{RegisterIndex, Registers}; use bit_field::BitField; use core::convert::{TryFrom, TryInto}; diff --git a/test/src/pci/config/mod.rs b/test/src/pci/config/mod.rs index 43a5bd45..71f437b7 100644 --- a/test/src/pci/config/mod.rs +++ b/test/src/pci/config/mod.rs @@ -1,4 +1,3 @@ - pub(crate) mod bar; mod common; pub(crate) mod type_spec; diff --git a/test/src/pci/config/type_spec/mod.rs b/test/src/pci/config/type_spec/mod.rs index 976c45d2..3433da27 100644 --- a/test/src/pci/config/type_spec/mod.rs +++ b/test/src/pci/config/type_spec/mod.rs @@ -1,4 +1,3 @@ - mod non_bridge; use super::{ diff --git a/test/src/pci/config/type_spec/non_bridge.rs b/test/src/pci/config/type_spec/non_bridge.rs index 8021bbbc..50180de7 100644 --- a/test/src/pci/config/type_spec/non_bridge.rs +++ b/test/src/pci/config/type_spec/non_bridge.rs @@ -1,4 +1,3 @@ - use super::{bar, Bar, RegisterIndex, Registers}; use log::debug; use x86_64::PhysAddr; diff --git a/test/src/pci/mod.rs b/test/src/pci/mod.rs index 408ac9d3..1475b2ff 100644 --- a/test/src/pci/mod.rs +++ b/test/src/pci/mod.rs @@ -1,4 +1,3 @@ - pub(crate) mod config; use config::{Bus, Device}; diff --git a/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs b/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs index 4007c4e8..2323158f 100644 --- a/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs +++ b/test/src/port/class_driver/mass_storage/scsi/command_data_block.rs @@ -1,4 +1,3 @@ - use byteorder::{BigEndian, ByteOrder}; #[derive(Copy, Clone)] diff --git a/test/src/port/class_driver/mass_storage/scsi/mod.rs b/test/src/port/class_driver/mass_storage/scsi/mod.rs index 327ce1ac..e45be3e5 100644 --- a/test/src/port/class_driver/mass_storage/scsi/mod.rs +++ b/test/src/port/class_driver/mass_storage/scsi/mod.rs @@ -1,4 +1,3 @@ - pub(super) mod command_data_block; pub(super) mod response; diff --git a/test/src/port/class_driver/mass_storage/scsi/response.rs b/test/src/port/class_driver/mass_storage/scsi/response.rs index 1674d7d8..210a2b13 100644 --- a/test/src/port/class_driver/mass_storage/scsi/response.rs +++ b/test/src/port/class_driver/mass_storage/scsi/response.rs @@ -1,4 +1,3 @@ - use byteorder::{BigEndian, ByteOrder}; use core::fmt; diff --git a/test/src/port/class_driver/mod.rs b/test/src/port/class_driver/mod.rs index a7e007b7..defb1ea1 100644 --- a/test/src/port/class_driver/mod.rs +++ b/test/src/port/class_driver/mod.rs @@ -1,4 +1,3 @@ - pub(crate) mod keyboard; pub(super) mod mass_storage; pub(crate) mod mouse; diff --git a/test/src/port/init/endpoints_initializer.rs b/test/src/port/init/endpoints_initializer.rs index 08e50bbe..a3ad429a 100644 --- a/test/src/port/init/endpoints_initializer.rs +++ b/test/src/port/init/endpoints_initializer.rs @@ -1,4 +1,3 @@ - use super::{descriptor_fetcher::DescriptorFetcher, fully_operational::FullyOperational}; use crate::{ exchanger, diff --git a/test/src/port/init/max_packet_size_setter.rs b/test/src/port/init/max_packet_size_setter.rs index a21f572e..ea465a71 100644 --- a/test/src/port/init/max_packet_size_setter.rs +++ b/test/src/port/init/max_packet_size_setter.rs @@ -1,4 +1,3 @@ - use super::{ descriptor_fetcher::DescriptorFetcher, slot_structures_initializer::SlotStructuresInitializer, }; diff --git a/test/src/port/init/mod.rs b/test/src/port/init/mod.rs index af46976c..95130585 100644 --- a/test/src/port/init/mod.rs +++ b/test/src/port/init/mod.rs @@ -1,4 +1,3 @@ - use fully_operational::FullyOperational; use resetter::Resetter; diff --git a/test/src/port/init/resetter.rs b/test/src/port/init/resetter.rs index 4f1e1256..dcbb17ab 100644 --- a/test/src/port/init/resetter.rs +++ b/test/src/port/init/resetter.rs @@ -1,4 +1,3 @@ - use super::slot_structures_initializer::SlotStructuresInitializer; use crate::structures::registers; use xhci::registers::PortRegisterSet; diff --git a/test/src/structures/descriptor.rs b/test/src/structures/descriptor.rs index 279c312f..a76c4c61 100644 --- a/test/src/structures/descriptor.rs +++ b/test/src/structures/descriptor.rs @@ -1,4 +1,3 @@ - use bit_field::BitField; use core::{convert::TryInto, ptr}; use num_derive::FromPrimitive; diff --git a/test/src/structures/mod.rs b/test/src/structures/mod.rs index 31cdc763..6093081f 100644 --- a/test/src/structures/mod.rs +++ b/test/src/structures/mod.rs @@ -1,4 +1,3 @@ - pub(crate) mod context; pub(crate) mod dcbaa; pub(crate) mod descriptor; diff --git a/test/src/structures/ring/mod.rs b/test/src/structures/ring/mod.rs index e8500f23..e33f4772 100644 --- a/test/src/structures/ring/mod.rs +++ b/test/src/structures/ring/mod.rs @@ -1,4 +1,3 @@ - pub(crate) mod command; pub(crate) mod event; pub(crate) mod transfer;