diff --git a/Cargo.lock b/Cargo.lock index ba08f33..276ec48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,167 +1,155 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "acpi" -version = "0.4.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30deabfb5818ba33c3963a7d182c974afb42d94b21ee229b5d005f3ac742b0c7" dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.10.1", + "log", + "rsdp", ] [[package]] name = "aml" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7669e841017880c2710777c46ec654272163379bbe55de6e17a2a2388d44d92" dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0", + "log", ] [[package]] name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bit_field" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" [[package]] -name = "bitflags" -version = "1.2.1" +name = "bit_field" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" [[package]] -name = "bootloader" -version = "0.8.3" +name = "bitflags" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "cast" -version = "0.2.3" +name = "bootloader" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "7a3c1ceed1cd9e61c7998100cc18c13d413aa40d018992b871ab8e7435ce6372" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "intrusive-collections" -version = "0.8.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1d0072a5e5c56adba35b9001f029ccc46f0e9ad0c7bcecd9b2f33b37123bca" dependencies = [ - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spin", ] [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rsdp" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d3add2fc55ef37511bcf81a08ee7a09eff07b23aae38b06a29024a38c604b1" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "solstice" version = "0.1.0" dependencies = [ - "acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bootloader 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "intrusive-collections 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "acpi", + "aml", + "arrayvec", + "bootloader", + "intrusive-collections", + "lazy_static", + "log", + "volatile 0.2.6", + "x86_64", ] [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] -name = "typenum" -version = "1.11.2" +name = "volatile" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" [[package]] name = "volatile" -version = "0.2.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c2dbd44eb8b53973357e6e207e370f0c1059990df850aca1eca8947cf464f0" [[package]] name = "x86_64" -version = "0.8.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c54a17492391c594753ce2a180142bec7ad2876543565c2a08aa11cddef251" dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0", + "bitflags", + "volatile 0.4.4", ] - -[metadata] -"checksum acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c18d706bdc322dd4f8f7930a5879ad8df3d78d4452a678d5419c72f9f69acea" -"checksum aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7669e841017880c2710777c46ec654272163379bbe55de6e17a2a2388d44d92" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum bootloader 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d596849a47f28abdea62d7a6a25c4f6e69c3d9b09b0a2877db6e9cda004ca993" -"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum intrusive-collections 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "163ff4f05115a819d7d8dab45661a2a38d7dde7ee93690a0b84cc819b78ba8c4" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" -"checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" -"checksum x86_64 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5d9e3e26fcb51976eafa310e8f2b7a5a83ae8c185443efe50cbc6534a4fffa0d" diff --git a/Cargo.toml b/Cargo.toml index d5e788e..02bdc8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,14 +31,14 @@ lto = true panic = "abort" [dependencies] -x86_64 = "0.8.3" -bootloader = { version = "0.8.3", features = ["map_physical_memory"] } +x86_64 = {version = "0.14.3", features = ["nightly"]} +bootloader = { version = "0.9.0", features = ["map_physical_memory"] } log = "0.4.8" volatile = "0.2.6" lazy_static = { version = "1.4.0", features = ["spin_no_std"] } -intrusive-collections = { version = "0.8.3", features = ["nightly"] } +intrusive-collections = { version = "0.9.1", features = ["nightly"] } arrayvec = { version = "0.5.1", default-features = false } -acpi = "0.4.0" +acpi = "3.0.0" aml = "0.4.0" #acpi = { path = "../acpi/acpi/" } #aml = { path = "../acpi/aml/" } diff --git a/bx_enh_dbg.ini b/bx_enh_dbg.ini new file mode 100644 index 0000000..2bc6660 --- /dev/null +++ b/bx_enh_dbg.ini @@ -0,0 +1,26 @@ +# bx_enh_dbg_ini +SeeReg[0] = TRUE +SeeReg[1] = TRUE +SeeReg[2] = TRUE +SeeReg[3] = TRUE +SeeReg[4] = FALSE +SeeReg[5] = FALSE +SeeReg[6] = FALSE +SeeReg[7] = FALSE +SingleCPU = FALSE +ShowIOWindows = TRUE +ShowButtons = TRUE +SeeRegColors = TRUE +ignoreNxtT = TRUE +ignSSDisasm = TRUE +UprCase = 0 +DumpInAsciiMode = 3 +isLittleEndian = TRUE +DefaultAsmLines = 512 +DumpWSIndex = 0 +DockOrder = 0x123 +ListWidthPix[0] = 484 +ListWidthPix[1] = 671 +ListWidthPix[2] = 765 +MainWindow = 0, 0, 1295, 370 +FontName = Normal diff --git a/scripts/bochs.sh b/scripts/bochs.sh index c16bc81..d558a38 100755 --- a/scripts/bochs.sh +++ b/scripts/bochs.sh @@ -1,6 +1,6 @@ #!/bin/sh set -e -bootimage build +cargo xbuild dd if=/dev/zero of=/tmp/solstice.img count=1008 bs=512 dd if=target/x86_64-solstice/debug/bootimage-solstice.bin of=/tmp/solstice.img conv=notrunc bochs -f scripts/.bochsrc -q diff --git a/scripts/debug.sh b/scripts/debug.sh new file mode 100755 index 0000000..877e482 --- /dev/null +++ b/scripts/debug.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -me +cargo xbuild +qemu-system-x86_64 -drive format=raw,file=../target/x86_64-solstice/debug/bootimage-solstice.bin -machine q35 -no-reboot -S -s -d int,guest_errors -no-shutdown \ No newline at end of file diff --git a/scripts/gdb.sh b/scripts/gdb.sh index 68908c0..9786b15 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -1,7 +1,6 @@ #!/bin/sh set -me -bootimage build -qemu-system-x86_64 -drive format=raw,file=target/x86_64-solstice/debug/bootimage-solstice.bin -no-reboot -S -s & +cargo xbuild +qemu-system-x86_64 -drive format=raw,file=../target/x86_64-solstice/debug/bootimage-solstice.bin -machine q35 -no-reboot -S -s & sleep 0.5 -gdb target/x86_64-solstice/debug/solstice -ex "target remote :1234" -pkill qemu +gdb ../target/x86_64-solstice/debug/solstice -ex "target remote :1234" \ No newline at end of file diff --git a/scripts/symextract.sh b/scripts/symextract.sh new file mode 100755 index 0000000..80e365e --- /dev/null +++ b/scripts/symextract.sh @@ -0,0 +1,2 @@ +#!/bin/sh +nm $1 | grep " T " | awk '{ print $1" "$3 }' > $1.sym \ No newline at end of file diff --git a/src/cpu/gdt.rs b/src/cpu/gdt.rs index bb4e6e7..29fe2ba 100644 --- a/src/cpu/gdt.rs +++ b/src/cpu/gdt.rs @@ -17,7 +17,6 @@ lazy_static! { tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { const STACK_SIZE: usize = 4096; static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); stack_start + STACK_SIZE @@ -54,15 +53,15 @@ pub fn load() { let null_segment = SegmentSelector::new(0, PrivilegeLevel::Ring0); let code_segment = SegmentSelector::new(1, PrivilegeLevel::Ring0); let tss_segment = SegmentSelector::new(2, PrivilegeLevel::Ring0); - seg::load_ds(null_segment); - seg::load_es(null_segment); - seg::load_fs(null_segment); - seg::load_gs(null_segment); - seg::load_ss(null_segment); + seg::load_es(SegmentSelector::new(0, PrivilegeLevel::Ring0)); + seg::load_fs(SegmentSelector::new(0, PrivilegeLevel::Ring0)); + seg::load_gs(SegmentSelector::new(0, PrivilegeLevel::Ring0)); + seg::load_ss(SegmentSelector::new(0, PrivilegeLevel::Ring0)); seg::set_cs(code_segment); load_tss(tss_segment); + } - debug!("gdt: loaded"); + //debug!("gdt: loaded"); } diff --git a/src/cpu/idt.rs b/src/cpu/idt.rs index ead4cb9..ba4a7fd 100644 --- a/src/cpu/idt.rs +++ b/src/cpu/idt.rs @@ -33,89 +33,89 @@ lazy_static! { pub fn load() { IDT.load(); - debug!("idt: loaded"); + //debug!("idt: loaded"); } test_case!(int3_handler, { x86_64::instructions::interrupts::int3(); }); -extern "x86-interrupt" fn divide_error_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn divide_error_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Zero Division\n{:#?}", frame); } -extern "x86-interrupt" fn debug_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn debug_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Debug\n{:#?}", frame); } -extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Non-Maskable Interrupt\n{:#?}", frame); } -extern "x86-interrupt" fn breakpoint_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn breakpoint_handler(frame: idt::InterruptStackFrame) { trace!("EXCEPTION: Breakpoint\n{:#?}", frame); } -extern "x86-interrupt" fn overflow_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn overflow_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Overflow\n{:#?}", frame); } -extern "x86-interrupt" fn bound_range_exceeded_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn bound_range_exceeded_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Bound Range Exceeded\n{:#?}", frame); } -extern "x86-interrupt" fn invalid_opcode_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn invalid_opcode_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Invalid Opcode\n{:#?}", frame); } -extern "x86-interrupt" fn device_not_available_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn device_not_available_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Device Not Available\n{:#?}", frame); } -extern "x86-interrupt" fn double_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) -> ! { +extern "x86-interrupt" fn double_fault_handler(frame: idt::InterruptStackFrame, error_code: u64) -> ! { panic!("EXCEPTION: Double Fault with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn invalid_tss_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn invalid_tss_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Invalid TSS with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn segment_not_present_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn segment_not_present_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Segment Not Present with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn stack_segment_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn stack_segment_fault_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Stack Segment Fault with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn general_protection_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn general_protection_fault_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: General Protection Fault with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn page_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: idt::PageFaultErrorCode) { +extern "x86-interrupt" fn page_fault_handler(frame: idt::InterruptStackFrame, error_code: idt::PageFaultErrorCode) { panic!("EXCEPTION: Page Fault with error code {:#?}\nAddress {:?}\n{:#?}", error_code, Cr2::read(), frame); } -extern "x86-interrupt" fn x87_floating_point_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn x87_floating_point_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: x87 Floating Point\n{:#?}", frame); } -extern "x86-interrupt" fn alignment_check_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn alignment_check_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Alignment Check with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn machine_check_handler(frame: &mut idt::InterruptStackFrame) -> ! { +extern "x86-interrupt" fn machine_check_handler(frame: idt::InterruptStackFrame) -> ! { panic!("EXCEPTION: Machine Check\n{:#?}", frame); } -extern "x86-interrupt" fn simd_floating_point_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn simd_floating_point_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: SIMD Floating Point\n{:#?}", frame); } -extern "x86-interrupt" fn virtualization_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn virtualization_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Virtualization\n{:#?}", frame); } -extern "x86-interrupt" fn security_exception_handler(frame: &mut idt::InterruptStackFrame, error_code: u64, ) { +extern "x86-interrupt" fn security_exception_handler(frame: idt::InterruptStackFrame, error_code: u64, ) { panic!("EXCEPTION: Security Exception with error code {}\n{:#?}", error_code, frame); } diff --git a/src/cpu/percpu.rs b/src/cpu/percpu.rs index 8611ca5..95ead67 100644 --- a/src/cpu/percpu.rs +++ b/src/cpu/percpu.rs @@ -1,7 +1,7 @@ use crate::mm::addr_space::AddrSpace; use arrayvec::ArrayVec; use core::sync::atomic::{AtomicUsize, Ordering}; - +#[allow(dead_code)] pub struct PerCpu { addr_space: *const AddrSpace, preempt_count: AtomicUsize, @@ -24,7 +24,7 @@ lazy_static! { cpus }; } - +#[allow(dead_code)] impl PerCpu { pub fn current() -> &'static PerCpu { &CPUS[0] // TODO: SMP diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index 3aee37d..6c82b7c 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -1,55 +1,155 @@ -use acpi::{Acpi, AcpiHandler, AmlTable, PhysicalMapping}; -use aml::{AmlContext, AmlError}; +use ::acpi::{AcpiHandler, AmlTable, PhysicalMapping}; +use aml::{AmlContext, AmlError, AmlValue}; use core::ptr::NonNull; -use x86_64::{PhysAddr, VirtAddr}; - -pub fn init() -> Acpi { - let acpi = unsafe { - acpi::search_for_rsdp_bios(&mut DummyAcpiHandler).expect("ACPI table parsing failed") - }; +use x86_64::{PhysAddr, VirtAddr, instructions::port::{PortRead,PortWrite}}; +use lazy_static::__Deref; +use acpi::{AcpiTables, InterruptModel}; +use acpi::sdt::Signature; +use acpi::platform::ProcessorInfo; +use crate::mm::phys_to_kernel_virt; +static mut SLP_TYPA:u64 = 0; +pub fn init() -> AcpiObject { + let our_acpi = unsafe {acpi::AcpiTables::search_for_rsdp_bios(Acpi)}.expect("ACPI table parsing failed"); debug!("acpi: found tables"); - let mut ctx = AmlContext::new(); - - if let Some(dsdt) = &acpi.dsdt { - parse_table(&mut ctx, dsdt).expect("AML DSDT parsing failed"); - debug!("acpi: parsed dsdt"); + match unsafe {core::ptr::read(&our_acpi.dsdt)} { + Some(dsdt) => { + parse_table(&mut ctx, &dsdt).expect("AML DSDT parsing failed"); + debug!("acpi: parsed dsdt"); + } + None => { + warn!("acpi: DSDT not found!"); + } } - - for (i, ssdt) in acpi.ssdts.iter().enumerate() { + for (i, ssdt) in our_acpi.ssdts.iter().enumerate() { parse_table(&mut ctx, ssdt).expect("AML SSDT parsing failed"); debug!("acpi: parsed ssdt {}", i); } - debug!("acpi: done!"); - acpi + let name = aml::AmlName::from_str("_S5_").expect("Could not get AmlName"); + let root = aml::AmlName::root(); + let name = ctx.namespace.search(&name, &root).expect("Could not get actual name"); + let v = ctx.namespace.get(name).expect("Could not get AmlValue"); + match v { + AmlValue::Name(p) => { + match p.deref() { + AmlValue::Package(v) => { + debug!("acpi: getting SLP_TYPA"); + unsafe { + SLP_TYPA = v[0].as_integer().unwrap() << 10; + } + } + _ => { + unreachable!(); + } + } + }, + _ => { + unreachable!(); + } + } + return AcpiObject::new(our_acpi); } +pub fn enable(acpi: &mut AcpiObject) { + let pm1a_control_block = unsafe {*(acpi.fadt.pm1a_control_block() + .expect("Could not get pm1a_control_block of ACPI!") + .address as *const u16)}; + let mut readval:u16 = unsafe { PortRead::read_from_port(pm1a_control_block) }; + if readval & 1 == 0 { + if acpi.fadt.smi_cmd_port != 0 && acpi.fadt.acpi_enable != 0 { + unsafe { PortWrite::write_to_port(acpi.fadt.smi_cmd_port as u16, acpi.fadt.acpi_enable); } + readval = unsafe { PortRead::read_from_port(pm1a_control_block) }; + while readval & 1 == 0 { + readval = unsafe { PortRead::read_from_port(pm1a_control_block) }; + } + match acpi.fadt.pm1b_control_block().expect("Could not get pm1b_control_block") { + None => {} + Some(pm1b_control_block_addr) => { + let pm1b_control_block = unsafe {*(pm1b_control_block_addr.address as *const u16)}; + readval = unsafe { PortRead::read_from_port(pm1b_control_block as u16) }; + while readval & 1 == 0 { + readval = unsafe { PortRead::read_from_port(pm1b_control_block as u16) }; + } + } + } + return; + } else { + debug!("ACPI cannot be enabled"); + } + } else { + warn!("ACPI already enabled"); + } +} +pub fn shutdown(acpi: &mut AcpiObject) { + let pm1a_control_block = unsafe {*(acpi.fadt.pm1a_control_block() + .expect("Could not get pm1a_control_block of ACPI!") + .address as *const u16)}; + loop { + unsafe { PortWrite::write_to_port(pm1a_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } + match acpi.fadt.pm1b_control_block().expect("Could not get pm1b_control_block") { + None => {} + Some(pm1b_control_block_addr) => { + let pm1b_control_block = unsafe {*(pm1b_control_block_addr.address as *const u16)}; + unsafe { PortWrite::write_to_port(pm1b_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } + } + } + //wait till dead + } +} fn parse_table(ctx: &mut AmlContext, table: &AmlTable) -> Result<(), AmlError> { - let virt = VirtAddr::from(PhysAddr::new(table.address as u64)); - + let virt = VirtAddr::new(table.address as u64); ctx.parse_table(unsafe { core::slice::from_raw_parts(virt.as_ptr(), table.length as usize) }) } -struct DummyAcpiHandler; - -impl AcpiHandler for DummyAcpiHandler { - fn map_physical_region( - &mut self, +pub struct Acpi; +impl Clone for Acpi { + fn clone(&self) -> Self { + Acpi + } +} +impl AcpiHandler for Acpi { + unsafe fn map_physical_region( + &self, physical_address: usize, size: usize, - ) -> PhysicalMapping { - let start_virt = VirtAddr::from(PhysAddr::new(physical_address as u64)); + ) -> PhysicalMapping { + let start_virt = phys_to_kernel_virt(PhysAddr::new(physical_address as u64)); + PhysicalMapping::new(physical_address, NonNull::new(start_virt.as_mut_ptr()).expect("acpi mapped null ptr"), size, size, Acpi) - PhysicalMapping { - physical_start: physical_address, - virtual_start: NonNull::new(start_virt.as_mut_ptr()).expect("acpi mapped null ptr"), - region_length: size, - mapped_length: size, - } } - fn unmap_physical_region(&mut self, _region: PhysicalMapping) {} + fn unmap_physical_region(_region: &PhysicalMapping) {} +} +pub struct AcpiObject { + pub tables: AcpiTables, + pub fadt: PhysicalMapping, + pub madt: PhysicalMapping, + pub interrupt_model: InterruptModel, + pub processor_info: Option +} +impl AcpiObject { + pub fn new(acpi_tables: AcpiTables) -> Self { + let madt = unsafe { acpi_tables.get_sdt::(Signature::MADT) } + .expect("Could not get MADT") + .expect("Could not get physical mapping"); + let fadt = unsafe { acpi_tables.get_sdt::(Signature::FADT) } + .expect("Could not get FADT") + .expect("Could not get physical mapping"); + let madt_result = madt.parse_interrupt_model() + .expect("Could not get interrupt model"); + AcpiObject { + tables: acpi_tables, + fadt, + madt, + interrupt_model: madt_result.0, + processor_info: madt_result.1 + } + } } +pub fn apic_supported() -> bool { + let cpuid = unsafe {core::arch::x86_64::__cpuid(0x1)}; + (cpuid.edx & (1 << 9)) != 0 +} \ No newline at end of file diff --git a/src/drivers/keyboard.rs b/src/drivers/keyboard.rs new file mode 100644 index 0000000..2d17984 --- /dev/null +++ b/src/drivers/keyboard.rs @@ -0,0 +1,58 @@ +use x86_64::instructions::port::{PortRead, PortWrite}; +use crate::drivers::keyboard::Ports::STATUS_COMMAND; +use crate::drivers::keyboard::StatusMasks::{INBUF_STATUS, OUTBUF_STATUS}; +use x86_64::structures::idt; +//for now, we're just going to support one layout +#[allow(non_camel_case_types)] +enum Ports { + DATA = 0x60, + //status register when read, command register when written to + STATUS_COMMAND = 0x64 +} +#[allow(dead_code)] +#[allow(non_camel_case_types)] +enum StatusMasks { + OUTBUF_STATUS = 0x01, + INBUF_STATUS = 0x02, + SYSFLAG = 0x04, + COMM_DATA = 0x08, + UNK1 = 0x10, + UNK2 = 0x20, + TIMEOUT_ERR = 0x40, + PARITY_ERR = 0x80 +} +unsafe fn keyboard_output_withwait(p:Ports, data:u8) { + loop { + let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); + if (sbyte & (INBUF_STATUS as u8)) == 0 { + break; + } + } + PortWrite::write_to_port(p as u16,data); +} +unsafe fn keyboard_input_withwait() -> u8 { + loop { + let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); + if (sbyte & (OUTBUF_STATUS as u8)) != 0 { + break; + } + } + return PortRead::read_from_port(Ports::DATA as u16); +} +pub fn init() { + unsafe { + keyboard_output_withwait(STATUS_COMMAND, 0xAE); + keyboard_output_withwait(STATUS_COMMAND, 0x20); + let mut response_byte:u8 = keyboard_input_withwait(); + response_byte |= 1; + keyboard_output_withwait(STATUS_COMMAND , 0x60); + keyboard_output_withwait(Ports::DATA, response_byte); + } +} +#[allow(unused_variables)] +pub extern "x86-interrupt" fn keyboard_interrupt_handler(frame: &mut idt::InterruptStackFrame) { + unsafe { + let incoming_byte: u8 = keyboard_input_withwait(); + info!("Key recieved: {}", incoming_byte); + } +} \ No newline at end of file diff --git a/src/drivers/vga/ransid.rs b/src/drivers/vga/ransid.rs index 32ccb63..5012f7a 100644 --- a/src/drivers/vga/ransid.rs +++ b/src/drivers/vga/ransid.rs @@ -44,7 +44,7 @@ pub struct ColorChar { pub style: u8, pub ascii: u8, } - +#[allow(dead_code)] fn create_style(bg: Color, fg: Color) -> u8 { let background = (bg as u8) << 4u8; let foreground = fg as u8; diff --git a/src/ds/sync/rwspinlock.rs b/src/ds/sync/rwspinlock.rs index 0b5c554..0c4efbc 100644 --- a/src/ds/sync/rwspinlock.rs +++ b/src/ds/sync/rwspinlock.rs @@ -8,7 +8,8 @@ use core::{ mem, ops::{Deref, DerefMut}, ptr::NonNull, - sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering}, + hint::spin_loop as cpu_relax, + sync::atomic::{AtomicUsize, Ordering}, }; use crate::cpu::percpu::PerCpu; diff --git a/src/ds/sync/spinlock.rs b/src/ds/sync/spinlock.rs index 2aa58fd..49caafb 100644 --- a/src/ds/sync/spinlock.rs +++ b/src/ds/sync/spinlock.rs @@ -2,7 +2,8 @@ use crate::cpu::percpu::PerCpu; use core::{ cell::UnsafeCell, ops::{Deref, DerefMut}, - sync::atomic::{spin_loop_hint, AtomicBool, Ordering}, + hint::spin_loop, + sync::atomic::{AtomicBool, Ordering}, }; pub struct SpinLock { @@ -24,9 +25,9 @@ impl SpinLock { pub fn lock(&self) -> SpinLockGuard { // Acquire the lock unsafe { PerCpu::current().preempt_inc() }; - while self.locked.compare_and_swap(false, true, Ordering::Acquire) { + while self.locked.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_err() { while self.locked.load(Ordering::Relaxed) { - spin_loop_hint(); + spin_loop(); } } @@ -39,7 +40,7 @@ impl SpinLock { pub fn try_lock(&self) -> Option> { unsafe { PerCpu::current().preempt_inc() }; - if !self.locked.compare_and_swap(false, true, Ordering::Acquire) { + if self.locked.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_err() { Some(SpinLockGuard { locked: &self.locked, data: unsafe { &mut *self.data.get() }, diff --git a/src/kernel.rs b/src/kernel.rs index eeff5c0..16b7ae8 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -4,13 +4,10 @@ use crate::{ mm::{map::MemoryMap, pmm::PhysAllocator}, }; use acpi::InterruptModel; -use apic::{LocalApic, XApic}; use bootloader::bootinfo::BootInfo; - pub fn kernel_main(info: &BootInfo) { drivers::serial::init(); drivers::vga::text_mode::init().unwrap(); - #[rustfmt::skip] { println!(" _____ _ _ _ Developed by:"); @@ -18,28 +15,25 @@ pub fn kernel_main(info: &BootInfo) { println!("| (___ ___ | |___| |_ _ ___ ___ - Crally"); println!(" \\___ \\ / _ \\| / __| __| |/ __/ _ \\ - Mehodin"); println!(" ____) | (_) | \\__ \\ |_| | (_| __/ - Alex8675"); - println!("|_____/ \\___/|_|___/\\__|_|\\___\\___|"); + println!("|_____/ \\___/|_|___/\\__|_|\\___\\___| - trash"); println!(); }; - + cpu::gdt::load(); cpu::idt::load(); - let map = MemoryMap::new(&info.memory_map); PhysAllocator::init(map); - let acpi = drivers::acpi::init(); - match acpi.interrupt_model { - None => panic!("unknown interrupt model"), - Some(InterruptModel::Pic { .. }) => panic!("unsupported acpi interrupt model"), - Some(InterruptModel::Apic { .. }) => { - if !XApic::is_supported() { + InterruptModel::Unknown { .. } => panic!("unsupported acpi interrupt model"), + InterruptModel::Apic { .. } => { + if !drivers::acpi::apic_supported() { error!("apic: xapic is not supported"); } else { info!("apic: detected xapic support"); } } + _ => {panic!("unknown acpi interrupt model")} }; } diff --git a/src/macros.rs b/src/macros.rs index 7ce9763..faff944 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -4,6 +4,9 @@ use crate::{drivers::vga::text_mode::Writer, ds::SpinLock}; use core::fmt; use lazy_static::lazy_static; use log::{Level, Log, Metadata, Record}; +use core::fmt::Debug; +use alloc::format; +use alloc::string::ToString; // Need a separate struct so we can implement Log trait pub struct ScreenLocker(SpinLock); @@ -11,6 +14,7 @@ pub struct ScreenLocker(SpinLock); pub struct ScreenWriter(Writer); impl fmt::Write for ScreenWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { #[cfg(any(debug_assertions, test))] { @@ -23,33 +27,36 @@ impl fmt::Write for ScreenWriter { Ok(()) } } - +// TODO: Macro formatting is broken, maybe due to broken memory alloc lazy_static! { pub static ref SCREEN: ScreenLocker = ScreenLocker(SpinLock::new(ScreenWriter(Writer::default()))); } - +#[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); } - +#[macro_export] macro_rules! println { - () => (print!("\n")); - ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); + () => ($crate::print!("\n")); + ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*)); } + // Lifted from standard library #[allow(unused_macros)] +#[macro_export] macro_rules! dbg { () => { - println!("[DEBUG {}:{}]", file!(), line!()); + $crate::println!("[DEBUG {}:{}]", file!(), line!()); }; ($val:expr) => { // Use of `match` here is intentional because it affects the lifetimes // of temporaries - https://stackoverflow.com/a/48732525/1063961 match $val { tmp => { - println!( + $crate::println!( "[\x1B[36mDEBUG\x1B[0m {}:{}] {} = {:#?}", file!(), line!(), @@ -60,17 +67,20 @@ macro_rules! dbg { } } }; - ($val:expr,) => { dbg!($val) }; + ($val:expr,) => { $crate::dbg!($val) }; ($($val:expr),+ $(,)?) => { - ($(dbg!($val)),+,) + ($($crate::dbg!($val)),+,) }; } - #[doc(hidden)] pub fn _print(args: fmt::Arguments) { use core::fmt::Write; x86_64::instructions::interrupts::without_interrupts(|| { - SCREEN.0.lock().write_fmt(args).unwrap(); + SCREEN + .0 + .lock() + .write_fmt(args) + .unwrap(); }); } @@ -90,14 +100,17 @@ impl Log for ScreenLocker { }; let reset = "\x1B[0m"; - - println!("[{}{}{}] {}", color, record.level(), reset, record.args()); + let args = match record.args().as_str() { + None => {"Cannot format log entry"} + Some(s) => {s} + }; //.to_string(); + println!("[{}{}{}] {}", color, record.level(), reset, args); } } fn flush(&self) {} } - +#[macro_export] macro_rules! test_case { ($test_name:ident, $body:expr) => { #[test_case] diff --git a/src/main.rs b/src/main.rs index 0fcb105..25561c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,9 @@ #![feature(asm)] #![feature(alloc_layout_extra)] #![feature(alloc_error_handler)] - +#![feature(raw_vec_internals)] +#![feature(ptr_internals)] +#![feature(allocator_api)] #[macro_use] extern crate log; @@ -20,14 +22,12 @@ extern crate alloc; #[macro_use] mod macros; - mod cpu; mod drivers; mod ds; mod kernel; mod mm; mod testing; - use bootloader::BootInfo; #[no_mangle] @@ -35,8 +35,7 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { kernel::kernel_main(boot_info); // Run tests - #[cfg(test)] - test_main(); + info!("nothing to do, halting..."); diff --git a/src/mm/addr_space.rs b/src/mm/addr_space.rs index 0e02523..698d963 100644 --- a/src/mm/addr_space.rs +++ b/src/mm/addr_space.rs @@ -2,8 +2,7 @@ use crate::{ds::RwSpinLock, mm::pmm::PhysAllocator}; use x86_64::{ registers::control::Cr3, structures::paging::{ - UnusedPhysFrame, - mapper::{MapToError, MapperAllSizes, MapperFlush}, + mapper::{MapToError, MapperFlush}, page::Size4KiB, FrameAllocator, Mapper, @@ -14,6 +13,7 @@ use x86_64::{ PhysAddr, VirtAddr, }; +use x86_64::structures::paging::{Translate, PhysFrame}; pub struct AddrSpace { table: RwSpinLock>, @@ -34,7 +34,7 @@ lazy_static! { } }; } - +#[allow(dead_code)] impl AddrSpace { pub fn kernel() -> &'static AddrSpace { &*KERNEL @@ -45,10 +45,10 @@ impl AddrSpace { virt: VirtAddr, phys: PhysAddr, flags: PageTableFlags, - ) -> Result, MapToError> { + ) -> Result, MapToError> { struct PhysAllocatorProxy; unsafe impl FrameAllocator for PhysAllocatorProxy { - fn allocate_frame(&mut self) -> Option> { + fn allocate_frame(&mut self) -> Option> { Some(PhysAllocator::alloc(0).start) } } @@ -64,11 +64,11 @@ impl AddrSpace { phys: PhysAddr, flags: PageTableFlags, alloc: &mut A, - ) -> Result, MapToError> { + ) -> Result, MapToError> { unsafe { self.table.write().map_to( Page::containing_address(virt), - UnusedPhysFrame::containing_address(phys), + PhysFrame::containing_address(phys), flags, alloc, ) diff --git a/src/mm/map.rs b/src/mm/map.rs index 9df0e5f..3db3858 100644 --- a/src/mm/map.rs +++ b/src/mm/map.rs @@ -1,5 +1,5 @@ // TODO: This should all be implemented in the bootloader, ideally -use crate::mm::{self, addr_space::AddrSpace}; +use crate::mm::{self, addr_space::AddrSpace, phys_to_kernel_virt}; use arrayvec::ArrayVec; use bootloader::bootinfo::{MemoryRegion, MemoryRegionType}; use core::{ @@ -7,7 +7,7 @@ use core::{ ptr::{self, NonNull}, }; use x86_64::{ - structures::paging::{FrameAllocator, PageSize, PageTableFlags, UnusedPhysFrame, PhysFrame, Size4KiB}, + structures::paging::{FrameAllocator, PageSize, PageTableFlags, PhysFrame, Size4KiB}, PhysAddr, VirtAddr, }; @@ -27,7 +27,7 @@ impl Region { size: offset, }, Region { - addr: PhysAddr::new(self.addr.as_usize() + offset), + addr: PhysAddr::new(self.addr.as_u64() + offset as u64), size: self.size - offset, }, ) @@ -57,7 +57,7 @@ impl MemoryMap { { bump.push(Region { addr: PhysAddr::new(reg.range.start_addr()), - size: reg.range.end_addr() - reg.range.start_addr(), + size: (reg.range.end_addr() - reg.range.start_addr()) as usize, }); } } @@ -101,24 +101,24 @@ impl MemoryMap { } fn push(&mut self, rg: Region) { - self.num_pages += rg.size / Size4KiB::SIZE; + self.num_pages += rg.size / Size4KiB::SIZE as usize; self.regions.push(rg); } } unsafe impl FrameAllocator for MemoryMap { - fn allocate_frame(&mut self) -> Option { + fn allocate_frame(&mut self) -> Option { let (idx, found_region) = self .regions .iter_mut() .enumerate() - .find(|(_, rg)| rg.size >= Size4KiB::SIZE) + .find(|(_, rg)| rg.size >= Size4KiB::SIZE as usize) .expect("bump allocator - out of memory"); let out = PhysFrame::containing_address(found_region.addr); - found_region.addr += Size4KiB::SIZE; - found_region.size -= Size4KiB::SIZE; + found_region.addr += Size4KiB::SIZE as usize; + found_region.size -= Size4KiB::SIZE as usize; self.num_pages -= 1; if found_region.size == 0 { @@ -129,15 +129,15 @@ unsafe impl FrameAllocator for MemoryMap { // Clear the page #[cfg(not(test))] unsafe { - let page: *mut u8 = VirtAddr::from(out.start_address()).as_mut_ptr(); + let page: *mut u8 = phys_to_kernel_virt(out.start_address()).as_u64() as *mut u8; core::intrinsics::write_bytes( page, if cfg!(debug_assertions) { 0xB8 } else { 0x00 }, - Size4KiB::SIZE, + Size4KiB::SIZE as usize, ) }; - unsafe { Some(UnusedPhysFrame::new(out)) } + unsafe { Some(PhysFrame::from(out)) } } } @@ -173,21 +173,21 @@ pub struct RegionBumpAllocator { impl RegionBumpAllocator { pub fn alloc(&mut self, layout: Layout) -> Option> { - let new_off = x86_64::align_up(self.offset + layout.size(), layout.align()); + let new_off = x86_64::align_up((self.offset + layout.size()) as u64, layout.align() as u64); - if new_off > self.size { + if new_off > self.size as u64 { None } else { let out = NonNull::new( VirtAddr::new( - self.start.as_usize() - + x86_64::align_up(self.offset, layout.align()) + self.start.as_u64() + + x86_64::align_up(self.offset as u64, layout.align() as u64) + super::PHYS_OFFSET, ) .as_mut_ptr(), ) .unwrap(); - self.offset = new_off; + self.offset = new_off as usize; Some(out) } } diff --git a/src/mm/mod.rs b/src/mm/mod.rs index 6a1ff1c..5ec6721 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -17,8 +17,8 @@ pub struct PageInfo { } pub fn phys_to_page_info(frame: PhysFrame) -> *const PageInfo { - let idx = frame.start_address().as_usize() / PAGE_SIZE; - let out_addr = PAGE_INFO_OFFSET + idx * core::mem::size_of::>(); + let idx = frame.start_address().as_u64() / PAGE_SIZE; + let out_addr = PAGE_INFO_OFFSET + idx * (core::mem::size_of::>()) as u64; // Check that it's not too large debug_assert!(out_addr < PAGE_INFO_OFFSET + 0x0000100000000000); @@ -27,10 +27,10 @@ pub fn phys_to_page_info(frame: PhysFrame) -> *const PageInfo { } pub fn kernel_virt_to_phys(virt: VirtAddr) -> PhysAddr { - debug_assert!(virt.start_address() >= PHYS_OFFSET); - PhysAddr::new(virt.start_address() - PHYS_OFFSET); + debug_assert!(virt.as_u64() >= PHYS_OFFSET); + PhysAddr::new(virt.as_u64() - PHYS_OFFSET) } pub fn phys_to_kernel_virt(phys: PhysAddr) -> VirtAddr { - VirtAddr::new(phys.as_u64()) + VirtAddr::new(phys.as_u64() + PHYS_OFFSET) } diff --git a/src/mm/pmm.rs b/src/mm/pmm.rs index 38554e4..3bfc46c 100644 --- a/src/mm/pmm.rs +++ b/src/mm/pmm.rs @@ -23,7 +23,7 @@ struct Zone { num_pages: u64, order_list: [&'static mut [Block]; MAX_ORDER as usize + 1], } - +#[allow(dead_code)] impl Zone { pub fn new(addr: PhysAddr, size: usize, blocks: &'static mut [Block]) -> Self { let num_pages = (size / super::PAGE_SIZE as usize) as u64; @@ -32,7 +32,7 @@ impl Zone { let mut blocks_in_order = num_pages; for (order, list) in order_list.iter_mut().enumerate() { - for block in list.iter_mut().take(blocks_in_order) { + for block in list.iter_mut().take(blocks_in_order as usize) { *block = Block::from_order(order as u8); } @@ -40,7 +40,7 @@ impl Zone { } let largest_order = - (num_pages.next_power_of_two().trailing_zeros() as usize).min(MAX_ORDER + 1); + (num_pages.next_power_of_two().trailing_zeros() as usize).min((MAX_ORDER + 1) as usize); for list in order_list[largest_order..].iter_mut() { list[0] = Block::from_order(largest_order as u8); } @@ -62,7 +62,7 @@ impl Zone { let max_order_blocks = x86_64::align_up(num_pages, MAX_ORDER_PAGES) / MAX_ORDER_PAGES; // TODO: This whole section is a bit of a hack - let mut tmp: [Option<&'static mut [Block]>; MAX_ORDER + 1] = [ + let mut tmp: [Option<&'static mut [Block]>; (MAX_ORDER + 1) as usize] = [ None, None, None, None, None, None, None, None, None, None, None, None, ]; @@ -79,7 +79,7 @@ impl Zone { // Iterate back up, setting parents to have the correct largest order value fn update_tree(&mut self, start_order: u8, mut idx: u64) { for current_order in start_order + 1..=MAX_ORDER as u8 { - let left_idx = idx & !1; + let left_idx = (idx & !1) as usize; let left = self.order_list[current_order as usize - 1][left_idx]; let right = self.order_list[current_order as usize - 1][left_idx + 1]; self.order_list[current_order as usize][idx as usize / 2] = Block::parent_state(left, right); @@ -109,10 +109,10 @@ impl Zone { } self.order_list[order as usize][idx as usize] = Block::Used; - self.update_tree(order, idx); + self.update_tree(order, idx as u64); - let start_frame = self.pages.start + 2u64.pow(order as u32) * idx; - let end_frame = self.pages.start + 2u64.pow(order as u32) * (idx + 1); + let start_frame = self.pages.start + 2u64.pow(order as u32) * idx as u64; + let end_frame = self.pages.start + 2u64.pow(order as u32) * (idx + 1) as u64; // Zero out region unsafe { @@ -128,11 +128,13 @@ impl Zone { } fn free(&mut self, range: PhysFrameRange) { - let order = range.len().trailing_zeros(); - debug_assert!(order <= MAX_ORDER); - debug_assert!(self.pages.contains_range(range)); + let len = range.end.start_address() - range.start.start_address(); + let order = len.trailing_zeros(); + debug_assert!(order <= MAX_ORDER as u32); + debug_assert!(self.pages.start.start_address() <= range.start.start_address()); + debug_assert!(self.pages.end.start_address() >= range.end.start_address()); - let idx = (range.start - self.pages.start) / range.len(); + let idx = (range.start - self.pages.start) / len; debug_assert_eq!(self.order_list[order as usize][idx as usize], Block::Used); self.order_list[order as usize][idx as usize] = Block::from_order(order as u8); @@ -150,6 +152,7 @@ impl core::fmt::Debug for Block { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Block::LargestFreeOrder(nzu) => { + fmt.write_fmt(format_args!("LargestFreeOrder({})", nzu.get() - 1)) } Block::Used => fmt.write_str("Used"), @@ -227,7 +230,7 @@ pub struct PhysAllocator { } pub static PMM: PhysAllocator = PhysAllocator::new(); - +#[allow(dead_code)] impl PhysAllocator { const fn new() -> Self { Self { @@ -280,7 +283,7 @@ impl PhysAllocator { pub fn free(range: PhysFrameRange) { for zone in PMM.zones.read().as_ref().unwrap() { let mut zone = zone.lock(); - if zone.pages.contains_range(range) { + if zone.pages.start.start_address() <= range.start.start_address() && zone.pages.end.start_address() >= range.end.start_address() { zone.free(range); return; } diff --git a/src/testing.rs b/src/testing.rs index 435f03b..2c8be10 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -1,7 +1,6 @@ #![allow(unused_imports)] #![allow(dead_code)] use core::panic::PanicInfo; - #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] enum ExitCode { diff --git a/x86_64/.gitignore b/x86_64/.gitignore deleted file mode 100644 index b5c891e..0000000 --- a/x86_64/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# Compiled files -*.o -*.so -*.rlib -*.dll - -# Executables -*.exe - -# Generated by Cargo -/target/ -Cargo.lock -/testing/target diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml deleted file mode 100644 index fca3773..0000000 --- a/x86_64/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -authors = [ - "Gerd Zellweger ", - "Eric Kidd ", - "Philipp Oppermann ", - "Dan Schatzberg ", - "John Ericson ", - "Rex Lunae ", -] -description = "Support for x86_64 specific instructions, registers, and structures." -documentation = "https://docs.rs/x86_64" -keywords = [ - "amd64", - "x86", - "x86_64", - "no_std", -] -categories = [ - "no-std", -] -license = "MIT/Apache-2.0" -name = "x86_64" -readme = "README.md" -repository = "https://github.com/rust-osdev/x86_64" -version = "0.7.2" -edition = "2018" - -[dependencies] -bit_field = "0.9.0" -bitflags = "1.0.4" - -[dependencies.cast] -version = "0.2.2" -default-features = false - -[dependencies.ux] -default-features = false -version = "0.1.3" - -[features] -deny-warnings = [] diff --git a/x86_64/LICENSE-MIT b/x86_64/LICENSE-MIT deleted file mode 100644 index 22e2806..0000000 --- a/x86_64/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Philipp Oppermann -Copyright (c) 2015 Gerd Zellweger -Copyright (c) 2015 The libcpu Developers - -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. diff --git a/x86_64/README.md b/x86_64/README.md deleted file mode 100644 index 0697e2b..0000000 --- a/x86_64/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Solstice x86_64 library - -FORKED FROM [rust-osdev/x86_64](https://github.com/rust-osdev/x86_64) diff --git a/x86_64/src/addr.rs b/x86_64/src/addr.rs deleted file mode 100644 index 3ed0109..0000000 --- a/x86_64/src/addr.rs +++ /dev/null @@ -1,357 +0,0 @@ -use core::convert::{Into, TryInto}; -use core::fmt; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - -use bit_field::BitField; -use ux::*; - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct VirtAddr(usize); - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct PhysAddr(usize); - -#[derive(Debug)] -pub struct VirtAddrNotValid(usize); - -impl From for VirtAddr { - fn from(phys: PhysAddr) -> VirtAddr { - VirtAddr::new(phys.as_usize() + 0xFFFF8000_00000000) - } -} - -impl From for PhysAddr { - fn from(virt: VirtAddr) -> PhysAddr { - PhysAddr::new(virt.as_usize() - 0xFFFF8000_00000000) - } -} - -impl VirtAddr { - pub fn new(addr: usize) -> VirtAddr { - Self::try_new(addr).expect( - "address passed to VirtAddr::new must not contain any data \ - in bits 48 to 64", - ) - } - - /// Tries to create a new canonical virtual address. - /// - /// This function tries to performs sign - /// extension of bit 47 to make the address canonical. It succeeds if bits 48 to 64 are - /// either a correct sign extension (i.e. copies of bit 47) or all null. Else, an error - /// is returned. - pub fn try_new(addr: usize) -> Result { - match addr.get_bits(47..64) { - 0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical - 1 => Ok(VirtAddr::new_unchecked(addr)), // address needs sign extension - other => Err(VirtAddrNotValid(other)), - } - } - - /// Creates a new canonical virtual address without checks. - /// - /// This function performs sign extension of bit 47 to make the address canonical, so - /// bits 48 to 64 are overwritten. If you want to check that these bits contain no data, - /// use `new` or `try_new`. - pub fn new_unchecked(mut addr: usize) -> VirtAddr { - if addr.get_bit(47) { - addr.set_bits(48..64, 0xffff); - } else { - addr.set_bits(48..64, 0); - } - VirtAddr(addr) - } - - /// Creates a virtual address that points to `0`. - pub const fn zero() -> VirtAddr { - VirtAddr(0) - } - - pub fn as_usize(self) -> usize { - self.0 - } - - /// Creates a virtual address from the given pointer - pub fn from_ptr(ptr: *const T) -> Self { - Self::new(ptr as usize) - } - - /// Converts the address to a raw pointer. - #[cfg(target_pointer_width = "64")] - pub fn as_ptr(self) -> *const T { - cast::usize(self.as_usize()) as *const T - } - - /// Converts the address to a mutable raw pointer. - #[cfg(target_pointer_width = "64")] - pub fn as_mut_ptr(self) -> *mut T { - self.as_ptr::() as *mut T - } - - /// Aligns the virtual address upwards to the given alignment. - /// - /// See the `align_up` function for more information. - pub fn align_up(self, align: U) -> Self - where - U: Into, - { - VirtAddr(align_up(self.0, align.into())) - } - - /// Aligns the virtual address downwards to the given alignment. - /// - /// See the `align_down` function for more information. - pub fn align_down(self, align: U) -> Self - where - U: Into, - { - VirtAddr(align_down(self.0, align.into())) - } - - /// Checks whether the virtual address has the demanded alignment. - pub fn is_aligned(self, align: U) -> bool - where - U: Into, - { - self.align_down(align) == self - } - - /// Returns the 12-bit page offset of this virtual address. - pub fn page_offset(&self) -> u12 { - u12::new((self.0 & 0xfff).try_into().unwrap()) - } - - /// Returns the 9-bit level 1 page table index. - pub fn p1_index(&self) -> u9 { - u9::new(((self.0 >> 12) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 2 page table index. - pub fn p2_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 3 page table index. - pub fn p3_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9 >> 9) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 4 page table index. - pub fn p4_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9 >> 9 >> 9) & 0o777).try_into().unwrap()) - } -} - -impl fmt::Debug for VirtAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VirtAddr({:#x})", self.0) - } -} - -impl Add for VirtAddr { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - VirtAddr::new(self.0 + rhs) - } -} - -impl AddAssign for VirtAddr { - fn add_assign(&mut self, rhs: usize) { - *self = *self + rhs; - } -} - -impl Sub for VirtAddr { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - VirtAddr::new(self.0.checked_sub(rhs).unwrap()) - } -} - -impl SubAssign for VirtAddr { - fn sub_assign(&mut self, rhs: usize) { - *self = *self - rhs; - } -} - -impl Sub for VirtAddr { - type Output = usize; - fn sub(self, rhs: VirtAddr) -> Self::Output { - self.as_usize().checked_sub(rhs.as_usize()).unwrap() - } -} - -#[derive(Debug)] -pub struct PhysAddrNotValid(usize); - -impl PhysAddr { - /// Creates a new physical address. - /// - /// Panics if a bit in the range 52 to 64 is set. - pub fn new(addr: usize) -> PhysAddr { - assert_eq!( - addr.get_bits(52..64), - 0, - "physical addresses must not have any bits in the range 52 to 64 set" - ); - PhysAddr(addr) - } - - /// Tries to create a new physical address. - /// - /// Fails if any bits in the range 52 to 64 are set. - pub fn try_new(addr: usize) -> Result { - match addr.get_bits(52..64) { - 0 => Ok(PhysAddr(addr)), // address is valid - other => Err(PhysAddrNotValid(other)), - } - } - - /// Converts the address to an `usize`. - pub fn as_usize(self) -> usize { - self.0 - } - - /// Convenience method for checking if a physical address is null. - pub fn is_null(&self) -> bool { - self.0 == 0 - } - - /// Aligns the physical address upwards to the given alignment. - /// - /// See the `align_up` function for more information. - pub fn align_up(self, align: U) -> Self - where - U: Into, - { - PhysAddr(align_up(self.0, align.into())) - } - - /// Aligns the physical address downwards to the given alignment. - /// - /// See the `align_down` function for more information. - pub fn align_down(self, align: U) -> Self - where - U: Into, - { - PhysAddr(align_down(self.0, align.into())) - } - - /// Checks whether the physical address has the demanded alignment. - pub fn is_aligned(self, align: U) -> bool - where - U: Into, - { - self.align_down(align) == self - } -} - -impl fmt::Debug for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "PhysAddr({:#x})", self.0) - } -} - -impl fmt::Binary for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::LowerHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Octal for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::UpperHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Add for PhysAddr { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - PhysAddr::new(self.0 + rhs) - } -} - -impl AddAssign for PhysAddr { - fn add_assign(&mut self, rhs: usize) { - *self = *self + rhs; - } -} - -impl Sub for PhysAddr { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - PhysAddr::new(self.0.checked_sub(rhs).unwrap()) - } -} - -impl SubAssign for PhysAddr { - fn sub_assign(&mut self, rhs: usize) { - *self = *self - rhs; - } -} - -impl Sub for PhysAddr { - type Output = usize; - fn sub(self, rhs: PhysAddr) -> Self::Output { - self.as_usize().checked_sub(rhs.as_usize()).unwrap() - } -} - -/// Align address downwards. -/// -/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be -/// a power of 2. -pub fn align_down(addr: usize, align: usize) -> usize { - assert!(align.is_power_of_two(), "`align` must be a power of two"); - addr & !(align - 1) -} - -/// Align address upwards. -/// -/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be -/// a power of 2. -pub fn align_up(addr: usize, align: usize) -> usize { - assert!(align.is_power_of_two(), "`align` must be a power of two"); - let align_mask = align - 1; - if addr & align_mask == 0 { - addr // already aligned - } else { - (addr | align_mask) + 1 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_align_up() { - // align 1 - assert_eq!(align_up(0, 1), 0); - assert_eq!(align_up(1234, 1), 1234); - assert_eq!(align_up(0xffffffffffffffff, 1), 0xffffffffffffffff); - // align 2 - assert_eq!(align_up(0, 2), 0); - assert_eq!(align_up(1233, 2), 1234); - assert_eq!(align_up(0xfffffffffffffffe, 2), 0xfffffffffffffffe); - // address 0 - assert_eq!(align_up(0, 128), 0); - assert_eq!(align_up(0, 1), 0); - assert_eq!(align_up(0, 2), 0); - assert_eq!(align_up(0, 0x8000000000000000), 0); - } -} diff --git a/x86_64/src/instructions/interrupts.rs b/x86_64/src/instructions/interrupts.rs deleted file mode 100644 index 95c526e..0000000 --- a/x86_64/src/instructions/interrupts.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Enabling and disabling interrupts - -/// Returns whether interrupts are enabled. -pub fn are_enabled() -> bool { - use crate::registers::rflags::{self, RFlags}; - - rflags::read().contains(RFlags::INTERRUPT_FLAG) -} - -/// Enable interrupts. -/// -/// This is a wrapper around the `sti` instruction. -#[inline] -pub fn enable() { - unsafe { - asm!("sti" :::: "volatile"); - } -} - -/// Disable interrupts. -/// -/// This is a wrapper around the `cli` instruction. -#[inline] -pub fn disable() { - unsafe { - asm!("cli" :::: "volatile"); - } -} - -/// Run a closure with disabled interrupts. -/// -/// Run the given closure, disabling interrupts before running it (if they aren't already disabled). -/// Afterwards, interrupts are enabling again if they were enabled before. -/// -/// If you have other `enable` and `disable` calls _within_ the closure, things may not work as expected. -/// -/// # Examples -/// -/// ```ignore -/// // interrupts are enabled -/// without_interrupts(|| { -/// // interrupts are disabled -/// without_interrupts(|| { -/// // interrupts are disabled -/// }); -/// // interrupts are still disabled -/// }); -/// // interrupts are enabled again -/// ``` -pub fn without_interrupts(f: F) -> R -where - F: FnOnce() -> R, -{ - // true if the interrupt flag is set (i.e. interrupts are enabled) - let saved_intpt_flag = are_enabled(); - - // if interrupts are enabled, disable them for now - if saved_intpt_flag { - disable(); - } - - // do `f` while interrupts are disabled - let ret = f(); - - // re-enable interrupts if they were previously enabled - if saved_intpt_flag { - enable(); - } - - // return the result of `f` to the caller - ret -} - -/// Cause a breakpoint exception by invoking the `int3` instruction. -#[inline] -pub fn int3() { - unsafe { - asm!("int3" :::: "volatile"); - } -} - -/// Generate a software interrupt by invoking the `int` instruction. -/// -/// This currently needs to be a macro because the `int` argument needs to be an -/// immediate. This macro will be replaced by a generic function when support for -/// const generics is implemented in Rust. -#[macro_export] -macro_rules! software_interrupt { - ($x:expr) => {{ - asm!("int $0" :: "N" ($x) :: "volatile"); - }}; -} diff --git a/x86_64/src/instructions/mod.rs b/x86_64/src/instructions/mod.rs deleted file mode 100644 index d8349f9..0000000 --- a/x86_64/src/instructions/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![cfg(target_arch = "x86_64")] - -//! Special x86_64 instructions. - -pub mod interrupts; -pub mod port; -pub mod random; -pub mod segmentation; -pub mod tables; -pub mod tlb; - -/// Halts the CPU until the next interrupt arrives. -#[inline] -pub fn hlt() { - unsafe { - asm!("hlt" :::: "volatile"); - } -} - -/// Emits a '[magic breakpoint](https://wiki.osdev.org/Bochs#Magic_Breakpoint)' instruction for the [Bochs](http://bochs.sourceforge.net/) CPU -/// emulator. Make sure to set `magic_break: enabled=1` in your `.bochsrc` file. -#[inline] -pub fn bochs_breakpoint() { - unsafe { - asm!("xchgw %bx, %bx" :::: "volatile"); - } -} diff --git a/x86_64/src/instructions/port.rs b/x86_64/src/instructions/port.rs deleted file mode 100644 index c08fa1d..0000000 --- a/x86_64/src/instructions/port.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! Access to I/O ports - -use core::marker::PhantomData; - -pub use crate::structures::port::{PortRead, PortReadWrite, PortWrite}; - -impl PortRead for u8 { - #[inline] - unsafe fn read_from_port(port: u16) -> u8 { - let value: u8; - asm!("inb %dx, %al" : "={al}"(value) : "{dx}"(port) :: "volatile"); - value - } -} - -impl PortRead for u16 { - #[inline] - unsafe fn read_from_port(port: u16) -> u16 { - let value: u16; - asm!("inw %dx, %ax" : "={ax}"(value) : "{dx}"(port) :: "volatile"); - value - } -} - -impl PortRead for u32 { - #[inline] - unsafe fn read_from_port(port: u16) -> u32 { - let value: u32; - asm!("inl %dx, %eax" : "={eax}"(value) : "{dx}"(port) :: "volatile"); - value - } -} - -impl PortWrite for u8 { - #[inline] - unsafe fn write_to_port(port: u16, value: u8) { - asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile"); - } -} - -impl PortWrite for u16 { - #[inline] - unsafe fn write_to_port(port: u16, value: u16) { - asm!("outw %ax, %dx" :: "{dx}"(port), "{ax}"(value) :: "volatile"); - } -} - -impl PortWrite for u32 { - #[inline] - unsafe fn write_to_port(port: u16, value: u32) { - asm!("outl %eax, %dx" :: "{dx}"(port), "{eax}"(value) :: "volatile"); - } -} - -impl PortReadWrite for u8 {} -impl PortReadWrite for u16 {} -impl PortReadWrite for u32 {} - -/// A read only I/O port. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PortReadOnly { - port: u16, - phantom: PhantomData, -} - -/// A write only I/O port. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PortWriteOnly { - port: u16, - phantom: PhantomData, -} - -/// An I/O port. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Port { - port: u16, - phantom: PhantomData, -} - -impl PortReadOnly { - /// Creates a read only I/O port with the given port number. - pub const fn new(port: u16) -> PortReadOnly { - PortReadOnly { - port: port, - phantom: PhantomData, - } - } - - /// Reads from the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn read(&mut self) -> T { - T::read_from_port(self.port) - } -} - -impl PortWriteOnly { - /// Creates a write only I/O port with the given port number. - pub const fn new(port: u16) -> PortWriteOnly { - PortWriteOnly { - port: port, - phantom: PhantomData, - } - } - - /// Writes to the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn write(&mut self, value: T) { - T::write_to_port(self.port, value) - } -} - -impl Port { - /// Creates an I/O port with the given port number. - pub const fn new(port: u16) -> Port { - Port { - port: port, - phantom: PhantomData, - } - } - - /// Reads from the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn read(&mut self) -> T { - T::read_from_port(self.port) - } - - /// Writes to the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn write(&mut self, value: T) { - T::write_to_port(self.port, value) - } -} diff --git a/x86_64/src/instructions/random.rs b/x86_64/src/instructions/random.rs deleted file mode 100644 index 17fe95b..0000000 --- a/x86_64/src/instructions/random.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Support for build-in RNGs - -#[derive(Copy, Clone, Debug)] -/// Used to obtain random numbers using x86_64's RDRAND opcode -pub struct RdRand(()); - -#[cfg(target_arch = "x86_64")] -impl RdRand { - /// Creates Some(RdRand) if RDRAND is supported, None otherwise - pub fn new() -> Option { - // RDRAND support indicated by CPUID page 01h, ecx bit 30 - // https://en.wikipedia.org/wiki/RdRand#Overview - let cpuid = unsafe { core::arch::x86_64::__cpuid(0x1) }; - if cpuid.ecx & (1 << 30) != 0 { - Some(RdRand(())) - } else { - None - } - } - - /// Uniformly sampled u64. - /// May fail in rare circumstances or heavy load. - #[inline] - pub fn get_u64(&self) -> Option { - let mut res: u64 = 0; - unsafe { - match core::arch::x86_64::_rdrand64_step(&mut res) { - 1 => Some(res), - x => { - debug_assert_eq!(x, 0, "rdrand64 returned non-binary value"); - None - } - } - } - } - /// Uniformly sampled u32. - /// May fail in rare circumstances or heavy load. - #[inline] - pub fn get_u32(&self) -> Option { - let mut res: u32 = 0; - unsafe { - match core::arch::x86_64::_rdrand32_step(&mut res) { - 1 => Some(res), - x => { - debug_assert_eq!(x, 0, "rdrand32 returned non-binary value"); - None - } - } - } - } - /// Uniformly sampled u16. - /// May fail in rare circumstances or heavy load. - #[inline] - pub fn get_u16(&self) -> Option { - let mut res: u16 = 0; - unsafe { - match core::arch::x86_64::_rdrand16_step(&mut res) { - 1 => Some(res), - x => { - debug_assert_eq!(x, 0, "rdrand16 returned non-binary value"); - None - } - } - } - } -} - -#[cfg(all(test, target_arch = "x86_64"))] -mod tests { - use super::*; - - #[test] - pub fn test_rdrand() { - let rand = RdRand::new(); - if is_x86_feature_detected!("rdrand") { - let rand = rand.unwrap(); - assert!(rand.get_u16().is_some()); - assert!(rand.get_u32().is_some()); - assert!(rand.get_u64().is_some()); - } else { - assert!(rand.is_none()); - } - } -} diff --git a/x86_64/src/instructions/segmentation.rs b/x86_64/src/instructions/segmentation.rs deleted file mode 100644 index 4283fb3..0000000 --- a/x86_64/src/instructions/segmentation.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Provides functions to read and write segment registers. - -use crate::structures::gdt::SegmentSelector; - -/// Reload code segment register. -/// -/// Note this is special since we can not directly move -/// to %cs. Instead we push the new segment selector -/// and return value on the stack and use lretq -/// to reload cs and continue at 1:. -pub unsafe fn set_cs(sel: SegmentSelector) { - #[inline(always)] - unsafe fn inner(sel: SegmentSelector) { - asm!("pushq $0; \ - leaq 1f(%rip), %rax; \ - pushq %rax; \ - lretq; \ - 1:" :: "ri" (u64::from(sel.0)) : "rax" "memory"); - } - - inner(sel) -} - -/// Reload stack segment register. -#[inline] -pub unsafe fn load_ss(sel: SegmentSelector) { - asm!("movw $0, %ss " :: "r" (sel.0) : "memory"); -} - -/// Reload data segment register. -#[inline] -pub unsafe fn load_ds(sel: SegmentSelector) { - asm!("movw $0, %ds " :: "r" (sel.0) : "memory"); -} - -/// Reload es segment register. -#[inline] -pub unsafe fn load_es(sel: SegmentSelector) { - asm!("movw $0, %es " :: "r" (sel.0) : "memory"); -} - -/// Reload fs segment register. -#[inline] -pub unsafe fn load_fs(sel: SegmentSelector) { - asm!("movw $0, %fs " :: "r" (sel.0) : "memory"); -} - -/// Reload gs segment register. -#[inline] -pub unsafe fn load_gs(sel: SegmentSelector) { - asm!("movw $0, %gs " :: "r" (sel.0) : "memory"); -} - -/// Returns the current value of the code segment register. -pub fn cs() -> SegmentSelector { - let segment: u16; - unsafe { asm!("mov %cs, $0" : "=r" (segment) ) }; - SegmentSelector(segment) -} diff --git a/x86_64/src/instructions/tables.rs b/x86_64/src/instructions/tables.rs deleted file mode 100644 index 9e582e9..0000000 --- a/x86_64/src/instructions/tables.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Functions to load GDT, IDT, and TSS structures. - -use crate::structures::gdt::SegmentSelector; - -pub use crate::structures::DescriptorTablePointer; - -/// Load a GDT. Use the -/// [`GlobalDescriptorTable`](crate::structures::gdt::GlobalDescriptorTable) struct for a high-level -/// interface to loading a GDT. -#[inline] -pub unsafe fn lgdt(gdt: &DescriptorTablePointer) { - asm!("lgdt ($0)" :: "r" (gdt) : "memory"); -} - -/// Load an IDT. Use the -/// [`InterruptDescriptorTable`](crate::structures::idt::InterruptDescriptorTable) struct for a high-level -/// interface to loading an IDT. -#[inline] -pub unsafe fn lidt(idt: &DescriptorTablePointer) { - asm!("lidt ($0)" :: "r" (idt) : "memory"); -} - -/// Load the task state register using the `ltr` instruction. -#[inline] -pub unsafe fn load_tss(sel: SegmentSelector) { - asm!("ltr $0" :: "r" (sel.0)); -} diff --git a/x86_64/src/instructions/tlb.rs b/x86_64/src/instructions/tlb.rs deleted file mode 100644 index 91a3e6a..0000000 --- a/x86_64/src/instructions/tlb.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Functions to flush the translation lookaside buffer (TLB). - -use crate::VirtAddr; - -/// Invalidate the given address in the TLB using the `invlpg` instruction. -#[inline] -pub fn flush(addr: VirtAddr) { - unsafe { asm!("invlpg ($0)" :: "r" (addr.as_usize()) : "memory") }; -} - -/// Invalidate the TLB completely by reloading the CR3 register. -#[inline] -pub fn flush_all() { - use crate::registers::control::Cr3; - let (frame, flags) = Cr3::read(); - unsafe { Cr3::write(frame, flags) } -} diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs deleted file mode 100644 index e435400..0000000 --- a/x86_64/src/lib.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! This crate provides x86_64 specific functions and data structures, -//! and access to various system registers. - -#![feature(const_fn)] -#![feature(asm)] -#![feature(abi_x86_interrupt)] -#![cfg_attr(not(test), no_std)] -#![deny(missing_debug_implementations)] - -/// Provides the non-standard-width integer types `u2`–`u63`. -/// -/// We use these integer types in various APIs, for example `u9` for page tables indices. -pub use ux; - -pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr}; - -pub mod instructions; -pub mod registers; -pub mod structures; - -mod addr; - -/// Represents a protection ring level. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[repr(u8)] -pub enum PrivilegeLevel { - /// Privilege-level 0 (most privilege): This level is used by critical system-software - /// components that require direct access to, and control over, all processor and system - /// resources. This can include BIOS, memory-management functions, and interrupt handlers. - Ring0 = 0, - - /// Privilege-level 1 (moderate privilege): This level is used by less-critical system- - /// software services that can access and control a limited scope of processor and system - /// resources. Software running at these privilege levels might include some device drivers - /// and library routines. The actual privileges of this level are defined by the - /// operating system. - Ring1 = 1, - - /// Privilege-level 2 (moderate privilege): Like level 1, this level is used by - /// less-critical system-software services that can access and control a limited scope of - /// processor and system resources. The actual privileges of this level are defined by the - /// operating system. - Ring2 = 2, - - /// Privilege-level 3 (least privilege): This level is used by application software. - /// Software running at privilege-level 3 is normally prevented from directly accessing - /// most processor and system resources. Instead, applications request access to the - /// protected processor and system resources by calling more-privileged service routines - /// to perform the accesses. - Ring3 = 3, -} - -impl PrivilegeLevel { - /// Creates a `PrivilegeLevel` from a numeric value. The value must be in the range 0..4. - /// - /// This function panics if the passed value is >3. - pub fn from_u16(value: u16) -> PrivilegeLevel { - match value { - 0 => PrivilegeLevel::Ring0, - 1 => PrivilegeLevel::Ring1, - 2 => PrivilegeLevel::Ring2, - 3 => PrivilegeLevel::Ring3, - i => panic!("{} is not a valid privilege level", i), - } - } -} diff --git a/x86_64/src/registers/control.rs b/x86_64/src/registers/control.rs deleted file mode 100644 index 05f1d0f..0000000 --- a/x86_64/src/registers/control.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Functions to read and write control registers. - -pub use super::model_specific::{Efer, EferFlags}; - -use bitflags::bitflags; - -/// Various control flags modifying the basic operation of the CPU. -#[derive(Debug)] -pub struct Cr0; - -bitflags! { - /// Configuration flags of the Cr0 register. - pub struct Cr0Flags: u64 { - /// Enables protected mode. - const PROTECTED_MODE_ENABLE = 1 << 0; - /// Enables monitoring of the coprocessor, typical for x87 instructions. - /// - /// Controls together with the `TASK_SWITCHED` flag whether a `wait` or `fwait` - /// instruction should cause a device-not-available exception. - const MONITOR_COPROCESSOR = 1 << 1; - /// Force all x87 and MMX instructions to cause an exception. - const EMULATE_COPROCESSOR = 1 << 2; - /// Automatically set to 1 on _hardware_ task switch. - /// - /// This flags allows lazily saving x87/MMX/SSE instructions on hardware context switches. - const TASK_SWITCHED = 1 << 3; - /// Enables the native error reporting mechanism for x87 FPU errors. - const NUMERIC_ERROR = 1 << 5; - /// Controls whether supervisor-level writes to read-only pages are inhibited. - /// - /// When set, it is not possible to write to read-only pages from ring 0. - const WRITE_PROTECT = 1 << 16; - /// Enables automatic alignment checking. - const ALIGNMENT_MASK = 1 << 18; - /// Ignored. Used to control write-back/write-through cache strategy on older CPUs. - const NOT_WRITE_THROUGH = 1 << 29; - /// Disables internal caches (only for some cases). - const CACHE_DISABLE = 1 << 30; - /// Enables page translation. - const PAGING = 1 << 31; - } -} - -/// Contains the Page Fault Linear Address (PFLA). -/// -/// When page fault occurs, the CPU sets this register to the accessed address. -#[derive(Debug)] -pub struct Cr2; - -/// Contains the physical address of the level 4 page table. -#[derive(Debug)] -pub struct Cr3; - -bitflags! { - /// Controls cache settings for the level 4 page table. - pub struct Cr3Flags: u64 { - /// Use a writethrough cache policy for the P4 table (else a writeback policy is used). - const PAGE_LEVEL_WRITETHROUGH = 1 << 3; - /// Disable caching for the P4 table. - const PAGE_LEVEL_CACHE_DISABLE = 1 << 4; - } -} - -#[cfg(target_arch = "x86_64")] -mod x86_64 { - use super::*; - use crate::structures::paging::PhysFrame; - use crate::{PhysAddr, VirtAddr}; - - impl Cr0 { - /// Read the current set of CR0 flags. - pub fn read() -> Cr0Flags { - Cr0Flags::from_bits_truncate(Self::read_raw()) - } - - /// Read the current raw CR0 value. - pub fn read_raw() -> u64 { - let value: u64; - unsafe { - asm!("mov %cr0, $0" : "=r" (value)); - } - value - } - - /// Write CR0 flags. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to violate memory - /// safety by e.g. disabling paging. - pub unsafe fn write(flags: Cr0Flags) { - let old_value = Self::read_raw(); - let reserved = old_value & !(Cr0Flags::all().bits()); - let new_value = reserved | flags.bits(); - - Self::write_raw(new_value); - } - - /// Write raw CR0 flags. - /// - /// Does _not_ preserve any values, including reserved fields. Unsafe because it's possible to violate memory - /// safety by e.g. disabling paging. - pub unsafe fn write_raw(value: u64) { - asm!("mov $0, %cr0" :: "r" (value) : "memory") - } - - /// Updates CR0 flags. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to violate memory - /// safety by e.g. disabling paging. - pub unsafe fn update(f: F) - where - F: FnOnce(&mut Cr0Flags), - { - let mut flags = Self::read(); - f(&mut flags); - Self::write(flags); - } - } - - impl Cr2 { - /// Read the current page fault linear address from the CR3 register. - pub fn read() -> VirtAddr { - let value: usize; - unsafe { - asm!("mov %cr2, $0" : "=r" (value)); - } - VirtAddr::new(value) - } - } - - impl Cr3 { - /// Read the current P4 table address from the CR3 register. - pub fn read() -> (PhysFrame, Cr3Flags) { - let value: usize; - unsafe { - asm!("mov %cr3, $0" : "=r" (value)); - } - let flags = Cr3Flags::from_bits_truncate(value as u64); - let addr = PhysAddr::new(value & 0x_000f_ffff_ffff_f000); - let frame = PhysFrame::containing_address(addr); - (frame, flags) - } - - /// Write a new P4 table address into the CR3 register. - /// - /// ## Safety - /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by - /// changing the page mapping. - pub unsafe fn write(frame: PhysFrame, flags: Cr3Flags) { - let addr = frame.start_address(); - let value = addr.as_usize() as u64 | flags.bits(); - asm!("mov $0, %cr3" :: "r" (value) : "memory") - } - } -} diff --git a/x86_64/src/registers/mod.rs b/x86_64/src/registers/mod.rs deleted file mode 100644 index f8bb993..0000000 --- a/x86_64/src/registers/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Access to various system and model specific registers. - -pub mod control; -pub mod model_specific; -pub mod rflags; - -/// Gets the current instruction pointer. Note that this is only approximate as it requires a few -/// instructions to execute. -#[inline(always)] -pub fn read_rip() -> u64 { - let rip: u64; - unsafe { - asm!( - "lea (%rip), $0" - : "=r"(rip) ::: "volatile" - ); - } - rip -} diff --git a/x86_64/src/registers/model_specific.rs b/x86_64/src/registers/model_specific.rs deleted file mode 100644 index 3f4a959..0000000 --- a/x86_64/src/registers/model_specific.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Functions to read and write control registers. - -use bitflags::bitflags; - -/// A model specific register. -#[derive(Debug)] -pub struct Msr(u32); - -impl Msr { - /// Create an instance from a register. - pub const fn new(reg: u32) -> Msr { - Msr(reg) - } -} - -/// The Extended Feature Enable Register. -#[derive(Debug)] -pub struct Efer; - -impl Efer { - /// The underlying model specific register. - pub const MSR: Msr = Msr(0xC0000080); -} - -bitflags! { - /// Flags of the Extended Feature Enable Register. - pub struct EferFlags: u64 { - /// Enables the `syscall` and `sysret` instructions. - const SYSTEM_CALL_EXTENSIONS = 1 << 0; - /// Activates long mode, requires activating paging. - const LONG_MODE_ENABLE = 1 << 8; - /// Indicates that long mode is active. - const LONG_MODE_ACTIVE = 1 << 10; - /// Enables the no-execute page-protection feature. - const NO_EXECUTE_ENABLE = 1 << 11; - /// Enables SVM extensions. - const SECURE_VIRTUAL_MACHINE_ENABLE = 1 << 12; - /// Enable certain limit checks in 64-bit mode. - const LONG_MODE_SEGMENT_LIMIT_ENABLE = 1 << 13; - /// Enable the `fxsave` and `fxrstor` instructions to execute faster in 64-bit mode. - const FAST_FXSAVE_FXRSTOR = 1 << 14; - /// Changes how the `invlpg` instruction operates on TLB entries of upper-level entries. - const TRANSLATION_CACHE_EXTENSION = 1 << 15; - } -} - -#[cfg(target_arch = "x86_64")] -mod x86_64 { - use super::*; - - impl Msr { - /// Read 64 bits msr register. - pub unsafe fn read(&self) -> u64 { - let (high, low): (u32, u32); - asm!("rdmsr" : "={eax}" (low), "={edx}" (high) : "{ecx}" (self.0) : "memory" : "volatile"); - ((high as u64) << 32) | (low as u64) - } - - /// Write 64 bits to msr register. - pub unsafe fn write(&mut self, value: u64) { - let low = value as u32; - let high = (value >> 32) as u32; - asm!("wrmsr" :: "{ecx}" (self.0), "{eax}" (low), "{edx}" (high) : "memory" : "volatile" ); - } - } - - impl Efer { - /// Read the current EFER flags. - pub fn read() -> EferFlags { - EferFlags::from_bits_truncate(Self::read_raw()) - } - - /// Read the current raw EFER flags. - pub fn read_raw() -> u64 { - unsafe { Self::MSR.read() } - } - - /// Write the EFER flags, preserving reserved values. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to break memory - /// safety, e.g. by disabling long mode. - pub unsafe fn write(flags: EferFlags) { - let old_value = Self::read_raw(); - let reserved = old_value & !(EferFlags::all().bits()); - let new_value = reserved | flags.bits(); - - Self::write_raw(new_value); - } - - /// Write the EFER flags. - /// - /// Does not preserve any bits, including reserved fields. Unsafe because it's possible to - /// break memory safety, e.g. by disabling long mode. - pub unsafe fn write_raw(flags: u64) { - Self::MSR.write(flags); - } - - /// Update EFER flags. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to break memory - /// safety, e.g. by disabling long mode. - pub unsafe fn update(f: F) - where - F: FnOnce(&mut EferFlags), - { - let mut flags = Self::read(); - f(&mut flags); - Self::write(flags); - } - } -} diff --git a/x86_64/src/registers/rflags.rs b/x86_64/src/registers/rflags.rs deleted file mode 100644 index b1fad31..0000000 --- a/x86_64/src/registers/rflags.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Processor state stored in the RFLAGS register. - -#[cfg(target_arch = "x86_64")] -pub use self::x86_64::*; - -use bitflags::bitflags; - -bitflags! { - /// The RFLAGS register. - pub struct RFlags: u64 { - /// Processor feature identification flag. - /// - /// If this flag is modifiable, the CPU supports CPUID. - const ID = 1 << 21; - /// Indicates that an external, maskable interrupt is pending. - /// - /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual - /// interrupts (CR4.PVI) are activated. - const VIRTUAL_INTERRUPT_PENDING = 1 << 20; - /// Virtual image of the INTERRUPT_FLAG bit. - /// - /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual - /// interrupts (CR4.PVI) are activated. - const VIRTUAL_INTERRUPT = 1 << 19; - /// Enable automatic alignment checking if CR0.AM is set. Only works if CPL is 3. - const ALIGNMENT_CHECK = 1 << 18; - /// Enable the virtual-8086 mode. - const VIRTUAL_8086_MODE = 1 << 17; - /// Allows to restart an instruction following an instrucion breakpoint. - const RESUME_FLAG = 1 << 16; - /// Used by `iret` in hardware task switch mode to determine if current task is nested. - const NESTED_TASK = 1 << 14; - /// The high bit of the I/O Privilege Level field. - /// - /// Specifies the privilege level required for executing I/O address-space instructions. - const IOPL_HIGH = 1 << 13; - /// The low bit of the I/O Privilege Level field. - /// - /// Specifies the privilege level required for executing I/O address-space instructions. - const IOPL_LOW = 1 << 12; - /// Set by hardware to indicate that the sign bit of the result of the last signed integer - /// operation differs from the source operands. - const OVERFLOW_FLAG = 1 << 11; - /// Determines the order in which strings are processed. - const DIRECTION_FLAG = 1 << 10; - /// Enable interrupts. - const INTERRUPT_FLAG = 1 << 9; - /// Enable single-step mode for debugging. - const TRAP_FLAG = 1 << 8; - /// Set by hardware if last arithmetic operation resulted in a negative value. - const SIGN_FLAG = 1 << 7; - /// Set by hardware if last arithmetic operation resulted in a zero value. - const ZERO_FLAG = 1 << 6; - /// Set by hardware if last arithmetic operation generated a carry ouf of bit 3 of the - /// result. - const AUXILIARY_CARRY_FLAG = 1 << 4; - /// Set by hardware if last result has an even number of 1 bits (only for some operations). - const PARITY_FLAG = 1 << 2; - /// Set by hardware if last arithmetic operation generated a carry out of the - /// most-significant bit of the result. - const CARRY_FLAG = 1 << 0; - } -} - -#[cfg(target_arch = "x86_64")] -mod x86_64 { - use super::*; - - /// Returns the current value of the RFLAGS register. - /// - /// Drops any unknown bits. - pub fn read() -> RFlags { - RFlags::from_bits_truncate(read_raw()) - } - - /// Returns the raw current value of the RFLAGS register. - pub fn read_raw() -> u64 { - let r: u64; - unsafe { asm!("pushfq; popq $0" : "=r"(r) :: "memory") }; - r - } - - /// Writes the RFLAGS register, preserves reserved bits. - pub fn write(flags: RFlags) { - let old_value = read_raw(); - let reserved = old_value & !(RFlags::all().bits()); - let new_value = reserved | flags.bits(); - - write_raw(new_value); - } - - /// Writes the RFLAGS register. - /// - /// Does not preserve any bits, including reserved bits. - pub fn write_raw(val: u64) { - unsafe { asm!("pushq $0; popfq" :: "r"(val) : "memory" "flags") }; - } -} diff --git a/x86_64/src/structures/gdt.rs b/x86_64/src/structures/gdt.rs deleted file mode 100644 index b340577..0000000 --- a/x86_64/src/structures/gdt.rs +++ /dev/null @@ -1,230 +0,0 @@ -//! Types for the Global Descriptor Table and segment selectors. - -use crate::structures::tss::TaskStateSegment; -use crate::PrivilegeLevel; -use bit_field::BitField; -use bitflags::bitflags; -use core::fmt; - -/// Specifies which element to load into a segment from -/// descriptor tables (i.e., is a index to LDT or GDT table -/// with some additional flags). -/// -/// See Intel 3a, Section 3.4.2 "Segment Selectors" -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(transparent)] -pub struct SegmentSelector(pub u16); - -impl SegmentSelector { - /// Creates a new SegmentSelector - /// - /// # Arguments - /// * `index`: index in GDT or LDT array (not the offset) - /// * `rpl`: the requested privilege level - pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector { - SegmentSelector(index << 3 | (rpl as u16)) - } - - /// Returns the GDT index. - pub fn index(&self) -> u16 { - self.0 >> 3 - } - - /// Returns the requested privilege level. - pub fn rpl(&self) -> PrivilegeLevel { - PrivilegeLevel::from_u16(self.0.get_bits(0..2)) - } -} - -impl fmt::Debug for SegmentSelector { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut s = f.debug_struct("SegmentSelector"); - s.field("index", &self.index()); - s.field("rpl", &self.rpl()); - s.finish() - } -} - -/// A 64-bit mode global descriptor table (GDT). -/// -/// In 64-bit mode, segmentation is not supported. The GDT is used nonetheless, for example for -/// switching between user and kernel mode or for loading a TSS. -/// -/// The GDT has a fixed size of 8 entries, trying to add more entries will panic. -/// -/// You do **not** need to add a null segment descriptor yourself - this is already done -/// internally. -/// -/// Data segment registers in ring 0 can be loaded with the null segment selector. When running in -/// ring 3, the `ss` register must point to a valid data segment which can be obtained through the -/// [`Descriptor::user_data_segment()`](Descriptor::user_data_segment) function. Code segments must -/// be valid and non-null at all times and can be obtained through the -/// [`Descriptor::kernel_code_segment()`](Descriptor::kernel_code_segment) and -/// [`Descriptor::user_code_segment()`](Descriptor::user_code_segment) in rings 0 and 3 -/// respectively. -/// -/// For more info, see: -/// [x86 Instruction Reference for `mov`](https://www.felixcloutier.com/x86/mov#64-bit-mode-exceptions), -/// [Intel Manual](https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf), -/// [AMD Manual](https://www.amd.com/system/files/TechDocs/24593.pdf) -/// -/// # Example -/// ``` -/// use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor}; -/// -/// let mut gdt = GlobalDescriptorTable::new(); -/// gdt.add_entry(Descriptor::kernel_code_segment()); -/// gdt.add_entry(Descriptor::user_code_segment()); -/// gdt.add_entry(Descriptor::user_data_segment()); -/// -/// // Add entry for TSS, call gdt.load() then update segment registers -/// ``` - -#[derive(Debug, Clone)] -pub struct GlobalDescriptorTable { - table: [u64; 8], - next_free: usize, -} - -impl GlobalDescriptorTable { - /// Creates an empty GDT. - pub fn new() -> GlobalDescriptorTable { - GlobalDescriptorTable { - table: [0; 8], - next_free: 1, - } - } - - /// Adds the given segment descriptor to the GDT, returning the segment selector. - /// - /// Panics if the GDT has no free entries left. - pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { - let index = match entry { - Descriptor::UserSegment(value) => self.push(value), - Descriptor::SystemSegment(value_low, value_high) => { - let index = self.push(value_low); - self.push(value_high); - index - } - }; - SegmentSelector::new(index as u16, PrivilegeLevel::Ring0) - } - - /// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the - /// segment registers; you **must** (re)load them yourself using [the appropriate - /// functions](crate::instructions::segmentation): - /// [load_ss](crate::instructions::segmentation::load_ss), - /// [set_cs](crate::instructions::segmentation::set_cs). - #[cfg(target_arch = "x86_64")] - pub fn load(&'static self) { - use crate::instructions::tables::{lgdt, DescriptorTablePointer}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self.table.as_ptr() as u64, - limit: (self.table.len() * size_of::() - 1) as u16, - }; - - unsafe { lgdt(&ptr) }; - } - - fn push(&mut self, value: u64) -> usize { - if self.next_free < self.table.len() { - let index = self.next_free; - self.table[index] = value; - self.next_free += 1; - index - } else { - panic!("GDT full"); - } - } -} - -/// A 64-bit mode segment descriptor. -/// -/// Segmentation is no longer supported in 64-bit mode, so most of the descriptor -/// contents are ignored. -#[derive(Debug, Clone)] -pub enum Descriptor { - /// Descriptor for a code or data segment. - /// - /// Since segmentation is no longer supported in 64-bit mode, almost all of - /// code and data descriptors is ignored. Only some flags are still used. - UserSegment(u64), - /// A system segment descriptor such as a LDT or TSS descriptor. - SystemSegment(u64, u64), -} - -bitflags! { - /// Flags for a GDT descriptor. Not all flags are valid for all descriptor types. - pub struct DescriptorFlags: u64 { - /// For data segments, this flag sets the segment as writable. Ignored for code segments. - const WRITABLE = 1 << 41; - /// Marks a code segment as “conforming”. This influences the privilege checks that - /// occur on control transfers. - const CONFORMING = 1 << 42; - /// This flag must be set for code segments. - const EXECUTABLE = 1 << 43; - /// This flag must be set for user segments (in contrast to system segments). - const USER_SEGMENT = 1 << 44; - /// Must be set for any segment, causes a segment not present exception if not set. - const PRESENT = 1 << 47; - /// Must be set for long mode code segments. - const LONG_MODE = 1 << 53; - - /// The DPL for this descriptor is Ring 3 - const DPL_RING_3 = 3 << 45; - } -} - -impl Descriptor { - /// Creates a segment descriptor for a long mode kernel code segment. - pub fn kernel_code_segment() -> Descriptor { - use self::DescriptorFlags as Flags; - - let flags = Flags::USER_SEGMENT | Flags::PRESENT | Flags::EXECUTABLE | Flags::LONG_MODE; - Descriptor::UserSegment(flags.bits()) - } - - /// Creates a segment descriptor for a long mode ring 3 data segment. - pub fn user_data_segment() -> Descriptor { - use self::DescriptorFlags as Flags; - - let flags = Flags::USER_SEGMENT | Flags::PRESENT | Flags::WRITABLE | Flags::DPL_RING_3; - Descriptor::UserSegment(flags.bits()) - } - - /// Creates a segment descriptor for a long mode ring 3 code segment. - pub fn user_code_segment() -> Descriptor { - use self::DescriptorFlags as Flags; - - let flags = Flags::USER_SEGMENT - | Flags::PRESENT - | Flags::EXECUTABLE - | Flags::LONG_MODE - | Flags::DPL_RING_3; - Descriptor::UserSegment(flags.bits()) - } - - /// Creates a TSS system descriptor for the given TSS. - pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor { - use self::DescriptorFlags as Flags; - use core::mem::size_of; - - let ptr = tss as *const _ as u64; - - let mut low = Flags::PRESENT.bits(); - // base - low.set_bits(16..40, ptr.get_bits(0..24)); - low.set_bits(56..64, ptr.get_bits(24..32)); - // limit (the `-1` in needed since the bound is inclusive) - low.set_bits(0..16, (size_of::() - 1) as u64); - // type (0b1001 = available 64-bit tss) - low.set_bits(40..44, 0b1001); - - let mut high = 0; - high.set_bits(0..32, ptr.get_bits(32..64)); - - Descriptor::SystemSegment(low, high) - } -} diff --git a/x86_64/src/structures/idt.rs b/x86_64/src/structures/idt.rs deleted file mode 100644 index f06bbd5..0000000 --- a/x86_64/src/structures/idt.rs +++ /dev/null @@ -1,765 +0,0 @@ -// Copyright 2017 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Provides types for the Interrupt Descriptor Table and its entries. - -use crate::{PrivilegeLevel, VirtAddr}; -use bit_field::BitField; -use bitflags::bitflags; -use core::fmt; -use core::marker::PhantomData; -use core::ops::{Deref, Index, IndexMut}; - -/// An Interrupt Descriptor Table with 256 entries. -/// -/// The first 32 entries are used for CPU exceptions. These entries can be either accessed through -/// fields on this struct or through an index operation, e.g. `idt[0]` returns the -/// first entry, the entry for the `divide_by_zero` exception. Note that the index access is -/// not possible for entries for which an error code is pushed. -/// -/// The remaining entries are used for interrupts. They can be accesed through index -/// operations on the idt, e.g. `idt[32]` returns the first interrupt entry, which is the 32th IDT -/// entry). -/// -/// -/// The field descriptions are taken from the -/// [AMD64 manual volume 2](https://support.amd.com/TechDocs/24593.pdf) -/// (with slight modifications). -#[allow(missing_debug_implementations)] -#[derive(Clone)] -#[repr(C)] -#[repr(align(16))] -pub struct InterruptDescriptorTable { - /// A divide by zero exception (`#DE`) occurs when the denominator of a DIV instruction or - /// an IDIV instruction is 0. A `#DE` also occurs if the result is too large to be - /// represented in the destination. - /// - /// The saved instruction pointer points to the instruction that caused the `#DE`. - /// - /// The vector number of the `#DE` exception is 0. - pub divide_by_zero: Entry, - - /// When the debug-exception mechanism is enabled, a `#DB` exception can occur under any - /// of the following circumstances: - /// - ///
- /// - /// - Instruction execution. - /// - Instruction single stepping. - /// - Data read. - /// - Data write. - /// - I/O read. - /// - I/O write. - /// - Task switch. - /// - Debug-register access, or general detect fault (debug register access when DR7.GD=1). - /// - Executing the INT1 instruction (opcode 0F1h). - /// - ///
- /// - /// `#DB` conditions are enabled and disabled using the debug-control register, `DR7` - /// and `RFLAGS.TF`. - /// - /// In the following cases, the saved instruction pointer points to the instruction that - /// caused the `#DB`: - /// - /// - Instruction execution. - /// - Invalid debug-register access, or general detect. - /// - /// In all other cases, the instruction that caused the `#DB` is completed, and the saved - /// instruction pointer points to the instruction after the one that caused the `#DB`. - /// - /// The vector number of the `#DB` exception is 1. - pub debug: Entry, - - /// An non maskable interrupt exception (NMI) occurs as a result of system logic - /// signaling a non-maskable interrupt to the processor. - /// - /// The processor recognizes an NMI at an instruction boundary. - /// The saved instruction pointer points to the instruction immediately following the - /// boundary where the NMI was recognized. - /// - /// The vector number of the NMI exception is 2. - pub non_maskable_interrupt: Entry, - - /// A breakpoint (`#BP`) exception occurs when an `INT3` instruction is executed. The - /// `INT3` is normally used by debug software to set instruction breakpoints by replacing - /// - /// The saved instruction pointer points to the byte after the `INT3` instruction. - /// - /// The vector number of the `#BP` exception is 3. - pub breakpoint: Entry, - - /// An overflow exception (`#OF`) occurs as a result of executing an `INTO` instruction - /// while the overflow bit in `RFLAGS` is set to 1. - /// - /// The saved instruction pointer points to the instruction following the `INTO` - /// instruction that caused the `#OF`. - /// - /// The vector number of the `#OF` exception is 4. - pub overflow: Entry, - - /// A bound-range exception (`#BR`) exception can occur as a result of executing - /// the `BOUND` instruction. The `BOUND` instruction compares an array index (first - /// operand) with the lower bounds and upper bounds of an array (second operand). - /// If the array index is not within the array boundary, the `#BR` occurs. - /// - /// The saved instruction pointer points to the `BOUND` instruction that caused the `#BR`. - /// - /// The vector number of the `#BR` exception is 5. - pub bound_range_exceeded: Entry, - - /// An invalid opcode exception (`#UD`) occurs when an attempt is made to execute an - /// invalid or undefined opcode. The validity of an opcode often depends on the - /// processor operating mode. - /// - ///
A `#UD` occurs under the following conditions: - /// - /// - Execution of any reserved or undefined opcode in any mode. - /// - Execution of the `UD2` instruction. - /// - Use of the `LOCK` prefix on an instruction that cannot be locked. - /// - Use of the `LOCK` prefix on a lockable instruction with a non-memory target location. - /// - Execution of an instruction with an invalid-operand type. - /// - Execution of the `SYSENTER` or `SYSEXIT` instructions in long mode. - /// - Execution of any of the following instructions in 64-bit mode: `AAA`, `AAD`, - /// `AAM`, `AAS`, `BOUND`, `CALL` (opcode 9A), `DAA`, `DAS`, `DEC`, `INC`, `INTO`, - /// `JMP` (opcode EA), `LDS`, `LES`, `POP` (`DS`, `ES`, `SS`), `POPA`, `PUSH` (`CS`, - /// `DS`, `ES`, `SS`), `PUSHA`, `SALC`. - /// - Execution of the `ARPL`, `LAR`, `LLDT`, `LSL`, `LTR`, `SLDT`, `STR`, `VERR`, or - /// `VERW` instructions when protected mode is not enabled, or when virtual-8086 mode - /// is enabled. - /// - Execution of any legacy SSE instruction when `CR4.OSFXSR` is cleared to 0. - /// - Execution of any SSE instruction (uses `YMM`/`XMM` registers), or 64-bit media - /// instruction (uses `MMXTM` registers) when `CR0.EM` = 1. - /// - Execution of any SSE floating-point instruction (uses `YMM`/`XMM` registers) that - /// causes a numeric exception when `CR4.OSXMMEXCPT` = 0. - /// - Use of the `DR4` or `DR5` debug registers when `CR4.DE` = 1. - /// - Execution of `RSM` when not in `SMM` mode. - /// - ///
- /// - /// The saved instruction pointer points to the instruction that caused the `#UD`. - /// - /// The vector number of the `#UD` exception is 6. - pub invalid_opcode: Entry, - - /// A device not available exception (`#NM`) occurs under any of the following conditions: - /// - ///
- /// - /// - An `FWAIT`/`WAIT` instruction is executed when `CR0.MP=1` and `CR0.TS=1`. - /// - Any x87 instruction other than `FWAIT` is executed when `CR0.EM=1`. - /// - Any x87 instruction is executed when `CR0.TS=1`. The `CR0.MP` bit controls whether the - /// `FWAIT`/`WAIT` instruction causes an `#NM` exception when `TS=1`. - /// - Any 128-bit or 64-bit media instruction when `CR0.TS=1`. - /// - ///
- /// - /// The saved instruction pointer points to the instruction that caused the `#NM`. - /// - /// The vector number of the `#NM` exception is 7. - pub device_not_available: Entry, - - /// A double fault (`#DF`) exception can occur when a second exception occurs during - /// the handling of a prior (first) exception or interrupt handler. - /// - ///
- /// - /// Usually, the first and second exceptions can be handled sequentially without - /// resulting in a `#DF`. In this case, the first exception is considered _benign_, as - /// it does not harm the ability of the processor to handle the second exception. In some - /// cases, however, the first exception adversely affects the ability of the processor to - /// handle the second exception. These exceptions contribute to the occurrence of a `#DF`, - /// and are called _contributory exceptions_. The following exceptions are contributory: - /// - /// - Invalid-TSS Exception - /// - Segment-Not-Present Exception - /// - Stack Exception - /// - General-Protection Exception - /// - /// A double-fault exception occurs in the following cases: - /// - /// - If a contributory exception is followed by another contributory exception. - /// - If a divide-by-zero exception is followed by a contributory exception. - /// - If a page fault is followed by another page fault or a contributory exception. - /// - /// If a third interrupting event occurs while transferring control to the `#DF` handler, - /// the processor shuts down. - /// - ///
- /// - /// The returned error code is always zero. The saved instruction pointer is undefined, - /// and the program cannot be restarted. - /// - /// The vector number of the `#DF` exception is 8. - pub double_fault: Entry, - - /// This interrupt vector is reserved. It is for a discontinued exception originally used - /// by processors that supported external x87-instruction coprocessors. On those processors, - /// the exception condition is caused by an invalid-segment or invalid-page access on an - /// x87-instruction coprocessor-instruction operand. On current processors, this condition - /// causes a general-protection exception to occur. - coprocessor_segment_overrun: Entry, - - /// An invalid TSS exception (`#TS`) occurs only as a result of a control transfer through - /// a gate descriptor that results in an invalid stack-segment reference using an `SS` - /// selector in the TSS. - /// - /// The returned error code is the `SS` segment selector. The saved instruction pointer - /// points to the control-transfer instruction that caused the `#TS`. - /// - /// The vector number of the `#TS` exception is 10. - pub invalid_tss: Entry, - - /// An segment-not-present exception (`#NP`) occurs when an attempt is made to load a - /// segment or gate with a clear present bit. - /// - /// The returned error code is the segment-selector index of the segment descriptor - /// causing the `#NP` exception. The saved instruction pointer points to the instruction - /// that loaded the segment selector resulting in the `#NP`. - /// - /// The vector number of the `#NP` exception is 11. - pub segment_not_present: Entry, - - /// An stack segment exception (`#SS`) can occur in the following situations: - /// - /// - Implied stack references in which the stack address is not in canonical - /// form. Implied stack references include all push and pop instructions, and any - /// instruction using `RSP` or `RBP` as a base register. - /// - Attempting to load a stack-segment selector that references a segment descriptor - /// containing a clear present bit. - /// - Any stack access that fails the stack-limit check. - /// - /// The returned error code depends on the cause of the `#SS`. If the cause is a cleared - /// present bit, the error code is the corresponding segment selector. Otherwise, the - /// error code is zero. The saved instruction pointer points to the instruction that - /// caused the `#SS`. - /// - /// The vector number of the `#NP` exception is 12. - pub stack_segment_fault: Entry, - - /// A general protection fault (`#GP`) can occur in various situations. Common causes include: - /// - /// - Executing a privileged instruction while `CPL > 0`. - /// - Writing a 1 into any register field that is reserved, must be zero (MBZ). - /// - Attempting to execute an SSE instruction specifying an unaligned memory operand. - /// - Loading a non-canonical base address into the `GDTR` or `IDTR`. - /// - Using WRMSR to write a read-only MSR. - /// - Any long-mode consistency-check violation. - /// - /// The returned error code is a segment selector, if the cause of the `#GP` is - /// segment-related, and zero otherwise. The saved instruction pointer points to - /// the instruction that caused the `#GP`. - /// - /// The vector number of the `#GP` exception is 13. - pub general_protection_fault: Entry, - - /// A page fault (`#PF`) can occur during a memory access in any of the following situations: - /// - /// - A page-translation-table entry or physical page involved in translating the memory - /// access is not present in physical memory. This is indicated by a cleared present - /// bit in the translation-table entry. - /// - An attempt is made by the processor to load the instruction TLB with a translation - /// for a non-executable page. - /// - The memory access fails the paging-protection checks (user/supervisor, read/write, - /// or both). - /// - A reserved bit in one of the page-translation-table entries is set to 1. A `#PF` - /// occurs for this reason only when `CR4.PSE=1` or `CR4.PAE=1`. - /// - /// The virtual (linear) address that caused the `#PF` is stored in the `CR2` register. - /// The saved instruction pointer points to the instruction that caused the `#PF`. - /// - /// The page-fault error code is described by the - /// [`PageFaultErrorCode`](struct.PageFaultErrorCode.html) struct. - /// - /// The vector number of the `#PF` exception is 14. - pub page_fault: Entry, - - /// vector nr. 15 - reserved_1: Entry, - - /// The x87 Floating-Point Exception-Pending exception (`#MF`) is used to handle unmasked x87 - /// floating-point exceptions. In 64-bit mode, the x87 floating point unit is not used - /// anymore, so this exception is only relevant when executing programs in the 32-bit - /// compatibility mode. - /// - /// The vector number of the `#MF` exception is 16. - pub x87_floating_point: Entry, - - /// An alignment check exception (`#AC`) occurs when an unaligned-memory data reference - /// is performed while alignment checking is enabled. An `#AC` can occur only when CPL=3. - /// - /// The returned error code is always zero. The saved instruction pointer points to the - /// instruction that caused the `#AC`. - /// - /// The vector number of the `#AC` exception is 17. - pub alignment_check: Entry, - - /// The machine check exception (`#MC`) is model specific. Processor implementations - /// are not required to support the `#MC` exception, and those implementations that do - /// support `#MC` can vary in how the `#MC` exception mechanism works. - /// - /// There is no reliable way to restart the program. - /// - /// The vector number of the `#MC` exception is 18. - pub machine_check: Entry, - - /// The SIMD Floating-Point Exception (`#XF`) is used to handle unmasked SSE - /// floating-point exceptions. The SSE floating-point exceptions reported by - /// the `#XF` exception are (including mnemonics): - /// - /// - IE: Invalid-operation exception (also called #I). - /// - DE: Denormalized-operand exception (also called #D). - /// - ZE: Zero-divide exception (also called #Z). - /// - OE: Overflow exception (also called #O). - /// - UE: Underflow exception (also called #U). - /// - PE: Precision exception (also called #P or inexact-result exception). - /// - /// The saved instruction pointer points to the instruction that caused the `#XF`. - /// - /// The vector number of the `#XF` exception is 19. - pub simd_floating_point: Entry, - - /// vector nr. 20 - pub virtualization: Entry, - - /// vector nr. 21-29 - reserved_2: [Entry; 9], - - /// The Security Exception (`#SX`) signals security-sensitive events that occur while - /// executing the VMM, in the form of an exception so that the VMM may take appropriate - /// action. (A VMM would typically intercept comparable sensitive events in the guest.) - /// In the current implementation, the only use of the `#SX` is to redirect external INITs - /// into an exception so that the VMM may — among other possibilities. - /// - /// The only error code currently defined is 1, and indicates redirection of INIT has occurred. - /// - /// The vector number of the ``#SX`` exception is 30. - pub security_exception: Entry, - - /// vector nr. 31 - reserved_3: Entry, - - /// User-defined interrupts can be initiated either by system logic or software. They occur - /// when: - /// - /// - System logic signals an external interrupt request to the processor. The signaling - /// mechanism and the method of communicating the interrupt vector to the processor are - /// implementation dependent. - /// - Software executes an `INTn` instruction. The `INTn` instruction operand provides - /// the interrupt vector number. - /// - /// Both methods can be used to initiate an interrupt into vectors 0 through 255. However, - /// because vectors 0 through 31 are defined or reserved by the AMD64 architecture, - /// software should not use vectors in this range for purposes other than their defined use. - /// - /// The saved instruction pointer depends on the interrupt source: - /// - /// - External interrupts are recognized on instruction boundaries. The saved instruction - /// pointer points to the instruction immediately following the boundary where the - /// external interrupt was recognized. - /// - If the interrupt occurs as a result of executing the INTn instruction, the saved - /// instruction pointer points to the instruction after the INTn. - interrupts: [Entry; 256 - 32], -} - -impl InterruptDescriptorTable { - /// Creates a new IDT filled with non-present entries. - pub const fn new() -> InterruptDescriptorTable { - InterruptDescriptorTable { - divide_by_zero: Entry::missing(), - debug: Entry::missing(), - non_maskable_interrupt: Entry::missing(), - breakpoint: Entry::missing(), - overflow: Entry::missing(), - bound_range_exceeded: Entry::missing(), - invalid_opcode: Entry::missing(), - device_not_available: Entry::missing(), - double_fault: Entry::missing(), - coprocessor_segment_overrun: Entry::missing(), - invalid_tss: Entry::missing(), - segment_not_present: Entry::missing(), - stack_segment_fault: Entry::missing(), - general_protection_fault: Entry::missing(), - page_fault: Entry::missing(), - reserved_1: Entry::missing(), - x87_floating_point: Entry::missing(), - alignment_check: Entry::missing(), - machine_check: Entry::missing(), - simd_floating_point: Entry::missing(), - virtualization: Entry::missing(), - reserved_2: [Entry::missing(); 9], - security_exception: Entry::missing(), - reserved_3: Entry::missing(), - interrupts: [Entry::missing(); 256 - 32], - } - } - - /// Resets all entries of this IDT in place. - pub fn reset(&mut self) { - self.divide_by_zero = Entry::missing(); - self.debug = Entry::missing(); - self.non_maskable_interrupt = Entry::missing(); - self.breakpoint = Entry::missing(); - self.overflow = Entry::missing(); - self.bound_range_exceeded = Entry::missing(); - self.invalid_opcode = Entry::missing(); - self.device_not_available = Entry::missing(); - self.double_fault = Entry::missing(); - self.coprocessor_segment_overrun = Entry::missing(); - self.invalid_tss = Entry::missing(); - self.segment_not_present = Entry::missing(); - self.stack_segment_fault = Entry::missing(); - self.general_protection_fault = Entry::missing(); - self.page_fault = Entry::missing(); - self.reserved_1 = Entry::missing(); - self.x87_floating_point = Entry::missing(); - self.alignment_check = Entry::missing(); - self.machine_check = Entry::missing(); - self.simd_floating_point = Entry::missing(); - self.virtualization = Entry::missing(); - self.reserved_2 = [Entry::missing(); 9]; - self.security_exception = Entry::missing(); - self.reserved_3 = Entry::missing(); - self.interrupts = [Entry::missing(); 256 - 32]; - } - - /// Loads the IDT in the CPU using the `lidt` command. - #[cfg(target_arch = "x86_64")] - pub fn load(&'static self) { - use crate::instructions::tables::{lidt, DescriptorTablePointer}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self as *const _ as u64, - limit: (size_of::() - 1) as u16, - }; - - unsafe { lidt(&ptr) }; - } -} - -impl Index for InterruptDescriptorTable { - type Output = Entry; - - /// Returns the IDT entry with the specified index. - /// - /// Panics if index is outside the IDT (i.e. greater than 255) or if the entry is an - /// exception that pushes an error code (use the struct fields for accessing these entries). - fn index(&self, index: usize) -> &Self::Output { - match index { - 0 => &self.divide_by_zero, - 1 => &self.debug, - 2 => &self.non_maskable_interrupt, - 3 => &self.breakpoint, - 4 => &self.overflow, - 5 => &self.bound_range_exceeded, - 6 => &self.invalid_opcode, - 7 => &self.device_not_available, - 9 => &self.coprocessor_segment_overrun, - 16 => &self.x87_floating_point, - 18 => &self.machine_check, - 19 => &self.simd_floating_point, - 20 => &self.virtualization, - i @ 32..=255 => &self.interrupts[i - 32], - i @ 15 | i @ 31 | i @ 21..=29 => panic!("entry {} is reserved", i), - i @ 8 | i @ 10..=14 | i @ 17 | i @ 30 => { - panic!("entry {} is an exception with error code", i) - } - i => panic!("no entry with index {}", i), - } - } -} - -impl IndexMut for InterruptDescriptorTable { - /// Returns a mutable reference to the IDT entry with the specified index. - /// - /// Panics if index is outside the IDT (i.e. greater than 255) or if the entry is an - /// exception that pushes an error code (use the struct fields for accessing these entries). - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - match index { - 0 => &mut self.divide_by_zero, - 1 => &mut self.debug, - 2 => &mut self.non_maskable_interrupt, - 3 => &mut self.breakpoint, - 4 => &mut self.overflow, - 5 => &mut self.bound_range_exceeded, - 6 => &mut self.invalid_opcode, - 7 => &mut self.device_not_available, - 9 => &mut self.coprocessor_segment_overrun, - 16 => &mut self.x87_floating_point, - 18 => &mut self.machine_check, - 19 => &mut self.simd_floating_point, - 20 => &mut self.virtualization, - i @ 32..=255 => &mut self.interrupts[i - 32], - i @ 15 | i @ 31 | i @ 21..=29 => panic!("entry {} is reserved", i), - i @ 8 | i @ 10..=14 | i @ 17 | i @ 30 => { - panic!("entry {} is an exception with error code", i) - } - i => panic!("no entry with index {}", i), - } - } -} - -/// An Interrupt Descriptor Table entry. -/// -/// The generic parameter can either be `HandlerFunc` or `HandlerFuncWithErrCode`, depending -/// on the interrupt vector. -#[derive(Debug, Clone, Copy, PartialEq)] -#[repr(C)] -pub struct Entry { - pointer_low: u16, - gdt_selector: u16, - options: EntryOptions, - pointer_middle: u16, - pointer_high: u32, - reserved: u32, - phantom: PhantomData, -} - -/// A handler function for an interrupt or an exception without error code. -pub type HandlerFunc = extern "x86-interrupt" fn(&mut InterruptStackFrame); -/// A handler function for an exception that pushes an error code. -pub type HandlerFuncWithErrCode = - extern "x86-interrupt" fn(&mut InterruptStackFrame, error_code: u64); -/// A page fault handler function that pushes a page fault error code. -pub type PageFaultHandlerFunc = - extern "x86-interrupt" fn(&mut InterruptStackFrame, error_code: PageFaultErrorCode); - -impl Entry { - /// Creates a non-present IDT entry (but sets the must-be-one bits). - pub const fn missing() -> Self { - Entry { - gdt_selector: 0, - pointer_low: 0, - pointer_middle: 0, - pointer_high: 0, - options: EntryOptions::minimal(), - reserved: 0, - phantom: PhantomData, - } - } - - /// Set the handler address for the IDT entry and sets the present bit. - /// - /// For the code selector field, this function uses the code segment selector currently - /// active in the CPU. - /// - /// The function returns a mutable reference to the entry's options that allows - /// further customization. - #[cfg(target_arch = "x86_64")] - fn set_handler_addr(&mut self, addr: u64) -> &mut EntryOptions { - use crate::instructions::segmentation; - - self.pointer_low = addr as u16; - self.pointer_middle = (addr >> 16) as u16; - self.pointer_high = (addr >> 32) as u32; - - self.gdt_selector = segmentation::cs().0; - - self.options.set_present(true); - &mut self.options - } -} - -macro_rules! impl_set_handler_fn { - ($h:ty) => { - #[cfg(target_arch = "x86_64")] - impl Entry<$h> { - /// Set the handler function for the IDT entry and sets the present bit. - /// - /// For the code selector field, this function uses the code segment selector currently - /// active in the CPU. - /// - /// The function returns a mutable reference to the entry's options that allows - /// further customization. - pub fn set_handler_fn(&mut self, handler: $h) -> &mut EntryOptions { - self.set_handler_addr(handler as u64) - } - } - }; -} - -impl_set_handler_fn!(HandlerFunc); -impl_set_handler_fn!(HandlerFuncWithErrCode); -impl_set_handler_fn!(PageFaultHandlerFunc); - -/// Represents the options field of an IDT entry. -#[repr(transparent)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct EntryOptions(u16); - -impl EntryOptions { - /// Creates a minimal options field with all the must-be-one bits set. - const fn minimal() -> Self { - EntryOptions(0b1110_0000_0000) - } - - /// Set or reset the preset bit. - pub fn set_present(&mut self, present: bool) -> &mut Self { - self.0.set_bit(15, present); - self - } - - /// Let the CPU disable hardware interrupts when the handler is invoked. By default, - /// interrupts are disabled on handler invocation. - pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self { - self.0.set_bit(8, !disable); - self - } - - /// Set the required privilege level (DPL) for invoking the handler. The DPL can be 0, 1, 2, - /// or 3, the default is 0. If CPL < DPL, a general protection fault occurs. - /// - /// This function panics for a DPL > 3. - pub fn set_privilege_level(&mut self, dpl: PrivilegeLevel) -> &mut Self { - self.0.set_bits(13..15, dpl as u16); - self - } - - /// Assigns a Interrupt Stack Table (IST) stack to this handler. The CPU will then always - /// switch to the specified stack before the handler is invoked. This allows kernels to - /// recover from corrupt stack pointers (e.g., on kernel stack overflow). - /// - /// An IST stack is specified by an IST index between 0 and 6 (inclusive). Using the same - /// stack for multiple interrupts can be dangerous when nested interrupts are possible. - /// - /// This function panics if the index is not in the range 0..7. - /// - /// ## Safety - /// This function is unsafe because the caller must ensure that the passed stack index is - /// valid and not used by other interrupts. Otherwise, memory safety violations are possible. - pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self { - // The hardware IST index starts at 1, but our software IST index - // starts at 0. Therefore we need to add 1 here. - self.0.set_bits(0..3, index + 1); - self - } -} - -/// Wrapper type for the exception stack frame pushed by the CPU. -/// -/// Identical to [`InterruptStackFrame`]. -#[deprecated(note = "This type was renamed to InterruptStackFrame.")] -pub type ExceptionStackFrame = InterruptStackFrame; - -/// Wrapper type for the interrupt stack frame pushed by the CPU. -/// -/// This type derefs to an [`InterruptStackFrameValue`], which allows reading the actual values. -/// -/// This wrapper type ensures that no accidental modification of the interrupt stack frame -/// occurs, which can cause undefined behavior (see the [`as_mut`](InterruptStackFrame::as_mut) -/// method for more information). -pub struct InterruptStackFrame { - value: InterruptStackFrameValue, -} - -impl InterruptStackFrame { - /// Gives mutable access to the contents of the interrupt stack frame. - /// - /// This function is unsafe since modifying the content of the interrupt stack frame - /// can easily lead to undefined behavior. For example, by writing an invalid value to - /// the instruction pointer field, the CPU can jump to arbitrary code at the end of the - /// interrupt. - pub unsafe fn as_mut(&mut self) -> &mut InterruptStackFrameValue { - &mut self.value - } -} - -impl Deref for InterruptStackFrame { - type Target = InterruptStackFrameValue; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -impl fmt::Debug for InterruptStackFrame { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.value.fmt(f) - } -} - -/// Represents the interrupt stack frame pushed by the CPU on interrupt or exception entry. -#[derive(Clone)] -#[repr(C)] -pub struct InterruptStackFrameValue { - /// This value points to the instruction that should be executed when the interrupt - /// handler returns. For most interrupts, this value points to the instruction immediately - /// following the last executed instruction. However, for some exceptions (e.g., page faults), - /// this value points to the faulting instruction, so that the instruction is restarted on - /// return. See the documentation of the `InterruptDescriptorTable` fields for more details. - pub instruction_pointer: VirtAddr, - /// The code segment selector, padded with zeros. - pub code_segment: u64, - /// The flags register before the interrupt handler was invoked. - pub cpu_flags: u64, - /// The stack pointer at the time of the interrupt. - pub stack_pointer: VirtAddr, - /// The stack segment descriptor at the time of the interrupt (often zero in 64-bit mode). - pub stack_segment: u64, -} - -impl fmt::Debug for InterruptStackFrameValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - struct Hex(u64); - impl fmt::Debug for Hex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:#x}", self.0) - } - } - - let mut s = f.debug_struct("InterruptStackFrame"); - s.field("instruction_pointer", &self.instruction_pointer); - s.field("code_segment", &self.code_segment); - s.field("cpu_flags", &Hex(self.cpu_flags)); - s.field("stack_pointer", &self.stack_pointer); - s.field("stack_segment", &self.stack_segment); - s.finish() - } -} - -bitflags! { - /// Describes an page fault error code. - #[repr(transparent)] - pub struct PageFaultErrorCode: u64 { - /// If this flag is set, the page fault was caused by a page-protection violation, - /// else the page fault was caused by a not-present page. - const PROTECTION_VIOLATION = 1 << 0; - - /// If this flag is set, the memory access that caused the page fault was a write. - /// Else the access that caused the page fault is a memory read. This bit does not - /// necessarily indicate the cause of the page fault was a read or write violation. - const CAUSED_BY_WRITE = 1 << 1; - - /// If this flag is set, an access in user mode (CPL=3) caused the page fault. Else - /// an access in supervisor mode (CPL=0, 1, or 2) caused the page fault. This bit - /// does not necessarily indicate the cause of the page fault was a privilege violation. - const USER_MODE = 1 << 2; - - /// If this flag is set, the page fault is a result of the processor reading a 1 from - /// a reserved field within a page-translation-table entry. - const MALFORMED_TABLE = 1 << 3; - - /// If this flag is set, it indicates that the access that caused the page fault was an - /// instruction fetch. - const INSTRUCTION_FETCH = 1 << 4; - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn size_test() { - use core::mem::size_of; - assert_eq!(size_of::>(), 16); - assert_eq!(size_of::(), 256 * 16); - } -} diff --git a/x86_64/src/structures/mod.rs b/x86_64/src/structures/mod.rs deleted file mode 100644 index 942399d..0000000 --- a/x86_64/src/structures/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Representations of various x86 specific structures and descriptor tables. - -pub mod gdt; -pub mod idt; -pub mod paging; -pub mod port; -pub mod tss; - -/// A struct describing a pointer to a descriptor table (GDT / IDT). -/// This is in a format suitable for giving to 'lgdt' or 'lidt'. -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct DescriptorTablePointer { - /// Size of the DT. - pub limit: u16, - /// Pointer to the memory region containing the DT. - pub base: u64, -} diff --git a/x86_64/src/structures/paging/frame.rs b/x86_64/src/structures/paging/frame.rs deleted file mode 100644 index 7325640..0000000 --- a/x86_64/src/structures/paging/frame.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! Abstractions for default-sized and huge physical memory frames. - -use crate::structures::paging::page::{PageSize, Size4KiB}; -use crate::PhysAddr; -use core::fmt; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - -/// A physical memory frame. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(C)] -pub struct PhysFrame { - start_address: PhysAddr, - size: PhantomData, -} - -impl PhysFrame { - /// Returns the frame that starts at the given virtual address. - /// - /// Returns an error if the address is not correctly aligned (i.e. is not a valid frame start). - pub fn from_start_address(address: PhysAddr) -> Result { - if !address.is_aligned(S::SIZE) { - return Err(()); - } - Ok(PhysFrame::containing_address(address)) - } - - /// Returns the frame that contains the given physical address. - pub fn containing_address(address: PhysAddr) -> Self { - PhysFrame { - start_address: address.align_down(S::SIZE), - size: PhantomData, - } - } - - /// Returns the start address of the frame. - pub fn start_address(&self) -> PhysAddr { - self.start_address - } - - /// Returns the size the frame (4KB, 2MB or 1GB). - pub fn size() -> usize { - S::SIZE - } - - /// Returns a range of frames, exclusive `end`. - pub fn range(start: PhysFrame, end: PhysFrame) -> PhysFrameRange { - PhysFrameRange { start, end } - } - - /// Returns a range of frames, inclusive `end`. - pub fn range_inclusive(start: PhysFrame, end: PhysFrame) -> PhysFrameRangeInclusive { - PhysFrameRangeInclusive { start, end } - } -} - -impl fmt::Debug for PhysFrame { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!( - "PhysFrame[{}]({:#x})", - S::SIZE_AS_DEBUG_STR, - self.start_address().as_usize() - )) - } -} - -impl Add for PhysFrame { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - PhysFrame::containing_address(self.start_address() + rhs * S::SIZE) - } -} - -impl AddAssign for PhysFrame { - fn add_assign(&mut self, rhs: usize) { - *self = self.clone() + rhs; - } -} - -impl Sub for PhysFrame { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - PhysFrame::containing_address(self.start_address() - rhs * S::SIZE) - } -} - -impl SubAssign for PhysFrame { - fn sub_assign(&mut self, rhs: usize) { - *self = self.clone() - rhs; - } -} - -impl Sub> for PhysFrame { - type Output = usize; - fn sub(self, rhs: PhysFrame) -> Self::Output { - (self.start_address - rhs.start_address) / S::SIZE - } -} - -/// An range of physical memory frames, exclusive the upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PhysFrameRange { - /// The start of the range, inclusive. - pub start: PhysFrame, - /// The end of the range, exclusive. - pub end: PhysFrame, -} - -impl PhysFrameRange { - /// Returns whether the range contains no frames. - pub fn is_empty(&self) -> bool { - !(self.start < self.end) - } - - pub fn len(&self) -> usize { - self.end - self.start - } - - pub fn contains(&self, frame: PhysFrame) -> bool { - self.start.start_address() <= frame.start_address() && frame.start_address() < self.end.start_address() - } - - pub fn contains_address(&self, addr: PhysAddr) -> bool { - self.contains(PhysFrame::::containing_address(addr)) - } - - pub fn contains_range(&self, range: Self) -> bool { - self.start.start_address() <= range.start.start_address() && range.end.start_address() <= self.end.start_address() - } -} - -impl Iterator for PhysFrameRange { - type Item = PhysFrame; - - fn next(&mut self) -> Option { - if self.start < self.end { - let frame = self.start.clone(); - self.start += 1; - Some(frame) - } else { - None - } - } -} - -impl fmt::Debug for PhysFrameRange { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PhysFrameRange") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -/// An range of physical memory frames, inclusive the upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PhysFrameRangeInclusive { - /// The start of the range, inclusive. - pub start: PhysFrame, - /// The start of the range, exclusive. - pub end: PhysFrame, -} - -impl PhysFrameRangeInclusive { - /// Returns whether the range contains no frames. - pub fn is_empty(&self) -> bool { - !(self.start <= self.end) - } -} - -impl Iterator for PhysFrameRangeInclusive { - type Item = PhysFrame; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let frame = self.start.clone(); - self.start += 1; - Some(frame) - } else { - None - } - } -} - -impl fmt::Debug for PhysFrameRangeInclusive { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PhysFrameRangeInclusive") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} diff --git a/x86_64/src/structures/paging/frame_alloc.rs b/x86_64/src/structures/paging/frame_alloc.rs deleted file mode 100644 index 6e80f15..0000000 --- a/x86_64/src/structures/paging/frame_alloc.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Traits for abstracting away frame allocation and deallocation. - -use crate::structures::paging::{PageSize, PhysFrame}; - -/// A trait for types that can allocate a frame of memory. -/// -/// This trait is unsafe to implement because the implementer must guarantee that -/// the `allocate_frame` method returns only unique unused frames. -pub unsafe trait FrameAllocator { - /// Allocate a frame of the appropriate size and return it if possible. - fn allocate_frame(&mut self) -> Option>; -} - -/// A trait for types that can deallocate a frame of memory. -pub trait FrameDeallocator { - /// Deallocate the given frame of memory. - fn deallocate_frame(&mut self, frame: PhysFrame); -} diff --git a/x86_64/src/structures/paging/mapper/mapped_page_table.rs b/x86_64/src/structures/paging/mapper/mapped_page_table.rs deleted file mode 100644 index 152219f..0000000 --- a/x86_64/src/structures/paging/mapper/mapped_page_table.rs +++ /dev/null @@ -1,560 +0,0 @@ -use crate::structures::paging::{ - frame::PhysFrame, - frame_alloc::FrameAllocator, - mapper::*, - page::{Page, Size1GiB, Size2MiB, Size4KiB}, - page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags}, -}; - -/// A Mapper implementation that relies on a PhysAddr to VirtAddr conversion function. -/// -/// This type requires that the all physical page table frames are mapped to some virtual -/// address. Normally, this is done by mapping the complete physical address space into -/// the virtual address space at some offset. Other mappings between physical and virtual -/// memory are possible too, as long as they can be calculated as an `PhysAddr` to -/// `VirtAddr` closure. -#[derive(Debug)] -pub struct MappedPageTable<'a, P: PhysToVirt> { - page_table_walker: PageTableWalker

, - level_4_table: &'a mut PageTable, -} - -impl<'a, P: PhysToVirt> MappedPageTable<'a, P> { - /// Creates a new `MappedPageTable` that uses the passed closure for converting virtual - /// to physical addresses. - /// - /// This function is unsafe because the caller must guarantee that the passed `phys_to_virt` - /// closure is correct. Also, the passed `level_4_table` must point to the level 4 page table - /// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g. - /// by writing to an illegal memory location. - pub unsafe fn new(level_4_table: &'a mut PageTable, phys_to_virt: P) -> Self { - Self { - level_4_table, - page_table_walker: PageTableWalker::new(phys_to_virt), - } - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_1gib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - - if !p3[page.p3_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p3[page.p3_index()].set_addr(frame.start_address(), flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_2mib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - let p2 = self - .page_table_walker - .create_next_table(&mut p3[page.p3_index()], allocator)?; - - if !p2[page.p2_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p2[page.p2_index()].set_addr(frame.start_address(), flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_4kib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - let p2 = self - .page_table_walker - .create_next_table(&mut p3[page.p3_index()], allocator)?; - let p1 = self - .page_table_walker - .create_next_table(&mut p2[page.p2_index()], allocator)?; - - if !p1[page.p1_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p1[page.p1_index()].set_frame(frame, flags); - - Ok(MapperFlush::new(page)) - } -} - -impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_1gib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - - let p3_entry = &mut p3[page.p3_index()]; - let flags = p3_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p3_entry.addr()))?; - - p3_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - p3[page.p3_index()].set_flags(flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.level_4_table; - let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; - - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p3_entry.addr())) - } -} - -impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_2mib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - - let p2_entry = &mut p2[page.p2_index()]; - let flags = p2_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p2_entry.addr()))?; - - p2_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - - if p2[page.p2_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p2[page.p2_index()].set_flags(flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.level_4_table; - let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; - let p2 = self.page_table_walker.next_table(&p3[page.p3_index()])?; - - let p2_entry = &p2[page.p2_index()]; - - if p2_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p2_entry.addr())) - } -} - -impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_4kib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - let p1 = self - .page_table_walker - .next_table_mut(&mut p2[page.p2_index()])?; - - let p1_entry = &mut p1[page.p1_index()]; - - let frame = p1_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - p1_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - let p1 = self - .page_table_walker - .next_table_mut(&mut p2[page.p2_index()])?; - - if p1[page.p1_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p1[page.p1_index()].set_flags(flags); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.level_4_table; - let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; - let p2 = self.page_table_walker.next_table(&p3[page.p3_index()])?; - let p1 = self.page_table_walker.next_table(&p2[page.p2_index()])?; - - let p1_entry = &p1[page.p1_index()]; - - if p1_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p1_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p1_entry.addr())) - } -} - -impl<'a, P: PhysToVirt> MapperAllSizes for MappedPageTable<'a, P> { - fn translate(&self, addr: VirtAddr) -> TranslateResult { - let p4 = &self.level_4_table; - let p3 = match self.page_table_walker.next_table(&p4[addr.p4_index()]) { - Ok(page_table) => page_table, - Err(PageTableWalkError::NotMapped) => return TranslateResult::PageNotMapped, - Err(PageTableWalkError::MappedToHugePage) => { - panic!("level 4 entry has huge page bit set") - } - }; - let p2 = match self.page_table_walker.next_table(&p3[addr.p3_index()]) { - Ok(page_table) => page_table, - Err(PageTableWalkError::NotMapped) => return TranslateResult::PageNotMapped, - Err(PageTableWalkError::MappedToHugePage) => { - let frame = PhysFrame::containing_address(p3[addr.p3_index()].addr()); - let offset = addr.as_usize() & 0o_777_777_7777; - return TranslateResult::Frame1GiB { frame, offset }; - } - }; - let p1 = match self.page_table_walker.next_table(&p2[addr.p2_index()]) { - Ok(page_table) => page_table, - Err(PageTableWalkError::NotMapped) => return TranslateResult::PageNotMapped, - Err(PageTableWalkError::MappedToHugePage) => { - let frame = PhysFrame::containing_address(p2[addr.p2_index()].addr()); - let offset = addr.as_usize() & 0o_777_7777; - return TranslateResult::Frame2MiB { frame, offset }; - } - }; - - let p1_entry = &p1[addr.p1_index()]; - - if p1_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - - let frame = match PhysFrame::from_start_address(p1_entry.addr()) { - Ok(frame) => frame, - Err(()) => return TranslateResult::InvalidFrameAddress(p1_entry.addr()), - }; - let offset = u64::from(addr.page_offset()) as usize; - TranslateResult::Frame4KiB { frame, offset } - } -} - -#[derive(Debug)] -struct PageTableWalker { - phys_to_virt: P, -} - -impl PageTableWalker

{ - pub unsafe fn new(phys_to_virt: P) -> Self { - Self { phys_to_virt } - } - - /// Internal helper function to get a reference to the page table of the next level. - /// - /// Returns `PageTableWalkError::NotMapped` if the entry is unused. Returns - /// `PageTableWalkError::MappedToHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - fn next_table<'b>( - &self, - entry: &'b PageTableEntry, - ) -> Result<&'b PageTable, PageTableWalkError> { - let page_table_ptr = self.phys_to_virt.phys_to_virt(entry.frame()?); - let page_table: &PageTable = unsafe { &*page_table_ptr }; - - Ok(page_table) - } - - /// Internal helper function to get a mutable reference to the page table of the next level. - /// - /// Returns `PageTableWalkError::NotMapped` if the entry is unused. Returns - /// `PageTableWalkError::MappedToHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - fn next_table_mut<'b>( - &self, - entry: &'b mut PageTableEntry, - ) -> Result<&'b mut PageTable, PageTableWalkError> { - let page_table_ptr = self.phys_to_virt.phys_to_virt(entry.frame()?); - let page_table: &mut PageTable = unsafe { &mut *page_table_ptr }; - - Ok(page_table) - } - - /// Internal helper function to create the page table of the next level if needed. - /// - /// If the passed entry is unused, a new frame is allocated from the given allocator, zeroed, - /// and the entry is updated to that address. If the passed entry is already mapped, the next - /// table is returned directly. - /// - /// Returns `MapToError::FrameAllocationFailed` if the entry is unused and the allocator - /// returned `None`. Returns `MapToError::ParentEntryHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - fn create_next_table<'b, A>( - &self, - entry: &'b mut PageTableEntry, - allocator: &mut A, - ) -> Result<&'b mut PageTable, PageTableCreateError> - where - A: FrameAllocator, - { - let created; - - if entry.is_unused() { - if let Some(frame) = allocator.allocate_frame() { - entry.set_frame(frame, PageTableFlags::PRESENT | PageTableFlags::WRITABLE); - created = true; - } else { - return Err(PageTableCreateError::FrameAllocationFailed); - } - } else { - created = false; - } - - let page_table = match self.next_table_mut(entry) { - Err(PageTableWalkError::MappedToHugePage) => { - Err(PageTableCreateError::MappedToHugePage)? - } - Err(PageTableWalkError::NotMapped) => panic!("entry should be mapped at this point"), - Ok(page_table) => page_table, - }; - - if created { - page_table.zero(); - } - Ok(page_table) - } -} - -#[derive(Debug)] -enum PageTableWalkError { - NotMapped, - MappedToHugePage, -} - -#[derive(Debug)] -enum PageTableCreateError { - MappedToHugePage, - FrameAllocationFailed, -} - -impl From for MapToError { - fn from(err: PageTableCreateError) -> Self { - match err { - PageTableCreateError::MappedToHugePage => MapToError::ParentEntryHugePage, - PageTableCreateError::FrameAllocationFailed => MapToError::FrameAllocationFailed, - } - } -} - -impl From for PageTableWalkError { - fn from(err: FrameError) -> Self { - match err { - FrameError::HugeFrame => PageTableWalkError::MappedToHugePage, - FrameError::FrameNotPresent => PageTableWalkError::NotMapped, - } - } -} - -impl From for UnmapError { - fn from(err: PageTableWalkError) -> Self { - match err { - PageTableWalkError::MappedToHugePage => UnmapError::ParentEntryHugePage, - PageTableWalkError::NotMapped => UnmapError::PageNotMapped, - } - } -} - -impl From for FlagUpdateError { - fn from(err: PageTableWalkError) -> Self { - match err { - PageTableWalkError::MappedToHugePage => FlagUpdateError::ParentEntryHugePage, - PageTableWalkError::NotMapped => FlagUpdateError::PageNotMapped, - } - } -} - -impl From for TranslateError { - fn from(err: PageTableWalkError) -> Self { - match err { - PageTableWalkError::MappedToHugePage => TranslateError::ParentEntryHugePage, - PageTableWalkError::NotMapped => TranslateError::PageNotMapped, - } - } -} - -/// Trait for converting a physical address to a virtual one. -/// -/// This only works if the physical address space is somehow mapped to the virtual -/// address space, e.g. at an offset. -pub trait PhysToVirt { - /// Translate the given physical frame to a virtual page table pointer. - fn phys_to_virt(&self, phys_frame: PhysFrame) -> *mut PageTable; -} - -impl PhysToVirt for T -where - T: Fn(PhysFrame) -> *mut PageTable, -{ - fn phys_to_virt(&self, phys_frame: PhysFrame) -> *mut PageTable { - self(phys_frame) - } -} diff --git a/x86_64/src/structures/paging/mapper/mod.rs b/x86_64/src/structures/paging/mapper/mod.rs deleted file mode 100644 index 57a6103..0000000 --- a/x86_64/src/structures/paging/mapper/mod.rs +++ /dev/null @@ -1,207 +0,0 @@ -//! Abstractions for reading and modifying the mapping of pages. - -pub use self::mapped_page_table::{MappedPageTable, PhysToVirt}; -#[cfg(target_arch = "x86_64")] -pub use self::offset_page_table::OffsetPageTable; -#[cfg(target_arch = "x86_64")] -pub use self::recursive_page_table::RecursivePageTable; - -use crate::structures::paging::{ - frame_alloc::FrameAllocator, page_table::PageTableFlags, Page, PageSize, PhysFrame, Size1GiB, - Size2MiB, Size4KiB, -}; -use crate::{PhysAddr, VirtAddr}; - -mod mapped_page_table; -mod offset_page_table; -mod recursive_page_table; - -/// This trait defines page table operations that work for all page sizes of the x86_64 -/// architecture. -pub trait MapperAllSizes: Mapper + Mapper + Mapper { - /// Return the frame that the given virtual address is mapped to and the offset within that - /// frame. - /// - /// If the given address has a valid mapping, the mapped frame and the offset within that - /// frame is returned. Otherwise an error value is returned. - /// - /// This function works with huge pages of all sizes. - fn translate(&self, addr: VirtAddr) -> TranslateResult; - - /// Translates the given virtual address to the physical address that it maps to. - /// - /// Returns `None` if there is no valid mapping for the given address. - /// - /// This is a convenience method. For more information about a mapping see the - /// [`translate`](MapperAllSizes::translate) method. - fn translate_addr(&self, addr: VirtAddr) -> Option { - match self.translate(addr) { - TranslateResult::PageNotMapped | TranslateResult::InvalidFrameAddress(_) => None, - TranslateResult::Frame4KiB { frame, offset } => Some(frame.start_address() + offset), - TranslateResult::Frame2MiB { frame, offset } => Some(frame.start_address() + offset), - TranslateResult::Frame1GiB { frame, offset } => Some(frame.start_address() + offset), - } - } -} - -/// The return value of the [`MapperAllSizes::translate`] function. -/// -/// If the given address has a valid mapping, a `Frame4KiB`, `Frame2MiB`, or `Frame1GiB` variant -/// is returned, depending on the size of the mapped page. The remaining variants indicate errors. -#[derive(Debug)] -pub enum TranslateResult { - /// The page is mapped to a physical frame of size 4KiB. - Frame4KiB { - /// The mapped frame. - frame: PhysFrame, - /// The offset whithin the mapped frame. - offset: usize, - }, - /// The page is mapped to a physical frame of size 2MiB. - Frame2MiB { - /// The mapped frame. - frame: PhysFrame, - /// The offset whithin the mapped frame. - offset: usize, - }, - /// The page is mapped to a physical frame of size 2MiB. - Frame1GiB { - /// The mapped frame. - frame: PhysFrame, - /// The offset whithin the mapped frame. - offset: usize, - }, - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// The page table entry for the given page points to an invalid physical address. - InvalidFrameAddress(PhysAddr), -} - -/// A trait for common page table operations on pages of size `S`. -pub trait Mapper { - /// Creates a new mapping in the page table. - /// - /// This function might need additional physical frames to create new page tables. These - /// frames are allocated from the `allocator` argument. At most three frames are required. - /// - /// This function is unsafe because the caller must guarantee that passed `frame` is - /// unused, i.e. not used for any other mappings. - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - frame_allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator; - - /// Removes a mapping from the page table and returns the frame that used to be mapped. - /// - /// Note that no page tables or pages are deallocated. - fn unmap(&mut self, page: Page) -> Result<(PhysFrame, MapperFlush), UnmapError>; - - /// Updates the flags of an existing mapping. - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError>; - - /// Return the frame that the specified page is mapped to. - /// - /// This function assumes that the page is mapped to a frame of size `S` and returns an - /// error otherwise. - fn translate_page(&self, page: Page) -> Result, TranslateError>; - - /// Maps the given frame to the virtual page with the same address. - /// - /// This function is unsafe because the caller must guarantee that the passed `frame` is - /// unused, i.e. not used for any other mappings. - unsafe fn identity_map( - &mut self, - frame: PhysFrame, - flags: PageTableFlags, - frame_allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - S: PageSize, - Self: Mapper, - { - let page = Page::containing_address(VirtAddr::new(frame.start_address().as_usize())); - self.map_to(page, frame, flags, frame_allocator) - } -} - -/// This type represents a page whose mapping has changed in the page table. -/// -/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs -/// to be flushed from the TLB before it's accessed. This type is returned from function that -/// change the mapping of a page to ensure that the TLB flush is not forgotten. -#[derive(Debug)] -#[must_use = "Page Table changes must be flushed or ignored."] -pub struct MapperFlush(Page); - -impl MapperFlush { - /// Create a new flush promise - fn new(page: Page) -> Self { - MapperFlush(page) - } - - /// Flush the page from the TLB to ensure that the newest mapping is used. - #[cfg(target_arch = "x86_64")] - pub fn flush(self) { - crate::instructions::tlb::flush(self.0.start_address()); - } - - /// Don't flush the TLB and silence the “must be used” warning. - pub fn ignore(self) {} -} - -/// This error is returned from `map_to` and similar methods. -#[derive(Debug)] -pub enum MapToError { - /// An additional frame was needed for the mapping process, but the frame allocator - /// returned `None`. - FrameAllocationFailed, - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of an already mapped huge page. - ParentEntryHugePage, - /// The given page is already mapped to a physical frame. - PageAlreadyMapped, -} - -/// An error indicating that an `unmap` call failed. -#[derive(Debug)] -pub enum UnmapError { - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of a huge page and can't be freed individually. - ParentEntryHugePage, - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// The page table entry for the given page points to an invalid physical address. - InvalidFrameAddress(PhysAddr), -} - -/// An error indicating that an `update_flags` call failed. -#[derive(Debug)] -pub enum FlagUpdateError { - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of a huge page and can't be freed individually. - ParentEntryHugePage, -} - -/// An error indicating that an `translate` call failed. -#[derive(Debug)] -pub enum TranslateError { - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of a huge page and can't be freed individually. - ParentEntryHugePage, - /// The page table entry for the given page points to an invalid physical address. - InvalidFrameAddress(PhysAddr), -} diff --git a/x86_64/src/structures/paging/mapper/offset_page_table.rs b/x86_64/src/structures/paging/mapper/offset_page_table.rs deleted file mode 100644 index 80ecc3b..0000000 --- a/x86_64/src/structures/paging/mapper/offset_page_table.rs +++ /dev/null @@ -1,151 +0,0 @@ -#![cfg(target_arch = "x86_64")] - -use crate::structures::paging::{frame::PhysFrame, mapper::*, page_table::PageTable}; - -/// A Mapper implementation that requires that the complete physically memory is mapped at some -/// offset in the virtual address space. -#[derive(Debug)] -pub struct OffsetPageTable<'a> { - inner: MappedPageTable<'a, PhysOffset>, -} - -impl<'a> OffsetPageTable<'a> { - /// Creates a new `OffsetPageTable` that uses the given offset for converting virtual - /// to physical addresses. - /// - /// This function is unsafe because the caller must guarantee that the passed `phys_offset` - /// is correct. Also, the passed `level_4_table` must point to the level 4 page table - /// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g. - /// by writing to an illegal memory location. - pub unsafe fn new(level_4_table: &'a mut PageTable, phys_offset: usize) -> Self { - let phys_offset = PhysOffset { - offset: phys_offset, - }; - Self { - inner: MappedPageTable::new(level_4_table, phys_offset), - } - } -} - -#[derive(Debug)] -struct PhysOffset { - offset: usize, -} - -impl PhysToVirt for PhysOffset { - fn phys_to_virt(&self, frame: PhysFrame) -> *mut PageTable { - let phys = frame.start_address().as_usize(); - let virt = VirtAddr::new(phys + self.offset); - virt.as_mut_ptr() - } -} - -// delegate all trait implementations to inner - -impl<'a> Mapper for OffsetPageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.inner.map_to(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - self.inner.unmap(page) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - self.inner.update_flags(page, flags) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - self.inner.translate_page(page) - } -} - -impl<'a> Mapper for OffsetPageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.inner.map_to(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - self.inner.unmap(page) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - self.inner.update_flags(page, flags) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - self.inner.translate_page(page) - } -} - -impl<'a> Mapper for OffsetPageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.inner.map_to(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - self.inner.unmap(page) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - self.inner.update_flags(page, flags) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - self.inner.translate_page(page) - } -} - -impl<'a> MapperAllSizes for OffsetPageTable<'a> { - fn translate(&self, addr: VirtAddr) -> TranslateResult { - self.inner.translate(addr) - } -} diff --git a/x86_64/src/structures/paging/mapper/recursive_page_table.rs b/x86_64/src/structures/paging/mapper/recursive_page_table.rs deleted file mode 100644 index 5865dc9..0000000 --- a/x86_64/src/structures/paging/mapper/recursive_page_table.rs +++ /dev/null @@ -1,621 +0,0 @@ -#![cfg(target_arch = "x86_64")] - -//! Access the page tables through a recursively mapped level 4 table. - -use super::*; -use crate::registers::control::Cr3; -use crate::structures::paging::{ - frame_alloc::FrameAllocator, - page::NotGiantPageSize, - page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags}, - Page, PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB, -}; -use crate::VirtAddr; -use ux::u9; - -/// A recursive page table is a last level page table with an entry mapped to the table itself. -/// -/// This recursive mapping allows accessing all page tables in the hierarchy: -/// -/// - To access the level 4 page table, we “loop“ (i.e. follow the recursively mapped entry) four -/// times. -/// - To access a level 3 page table, we “loop” three times and then use the level 4 index. -/// - To access a level 2 page table, we “loop” two times, then use the level 4 index, then the -/// level 3 index. -/// - To access a level 1 page table, we “loop” once, then use the level 4 index, then the -/// level 3 index, then the level 2 index. -/// -/// This struct implements the `Mapper` trait. -#[derive(Debug)] -pub struct RecursivePageTable<'a> { - p4: &'a mut PageTable, - recursive_index: u9, -} - -impl<'a> RecursivePageTable<'a> { - /// Creates a new RecursivePageTable from the passed level 4 PageTable. - /// - /// The page table must be recursively mapped, that means: - /// - /// - The page table must have one recursive entry, i.e. an entry that points to the table - /// itself. - /// - The reference must use that “loop”, i.e. be of the form `0o_xxx_xxx_xxx_xxx_0000` - /// where `xxx` is the recursive entry. - /// - The page table must be active, i.e. the CR3 register must contain its physical address. - /// - /// Otherwise `Err(())` is returned. - pub fn new(table: &'a mut PageTable) -> Result { - let page = Page::containing_address(VirtAddr::new(table as *const _ as usize)); - let recursive_index = page.p4_index(); - - if page.p3_index() != recursive_index - || page.p2_index() != recursive_index - || page.p1_index() != recursive_index - { - return Err(()); - } - if Ok(Cr3::read().0) != table[recursive_index].frame() { - return Err(()); - } - - Ok(RecursivePageTable { - p4: table, - recursive_index, - }) - } - - /// Creates a new RecursivePageTable without performing any checks. - /// - /// The `recursive_index` parameter must be the index of the recursively mapped entry. - pub unsafe fn new_unchecked(table: &'a mut PageTable, recursive_index: u9) -> Self { - RecursivePageTable { - p4: table, - recursive_index, - } - } - - /// Internal helper function to create the page table of the next level if needed. - /// - /// If the passed entry is unused, a new frame is allocated from the given allocator, zeroed, - /// and the entry is updated to that address. If the passed entry is already mapped, the next - /// table is returned directly. - /// - /// The `next_page_table` page must be the page of the next page table in the hierarchy. - /// - /// Returns `MapToError::FrameAllocationFailed` if the entry is unused and the allocator - /// returned `None`. Returns `MapToError::ParentEntryHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - unsafe fn create_next_table<'b, A>( - entry: &'b mut PageTableEntry, - next_table_page: Page, - allocator: &mut A, - ) -> Result<&'b mut PageTable, MapToError> - where - A: FrameAllocator, - { - /// This inner function is used to limit the scope of `unsafe`. - /// - /// This is a safe function, so we need to use `unsafe` blocks when we do something unsafe. - fn inner<'b, A>( - entry: &'b mut PageTableEntry, - next_table_page: Page, - allocator: &mut A, - ) -> Result<&'b mut PageTable, MapToError> - where - A: FrameAllocator, - { - use crate::structures::paging::PageTableFlags as Flags; - - let created; - - if entry.is_unused() { - if let Some(frame) = allocator.allocate_frame() { - entry.set_frame(frame, Flags::PRESENT | Flags::WRITABLE); - created = true; - } else { - return Err(MapToError::FrameAllocationFailed); - } - } else { - created = false; - } - if entry.flags().contains(Flags::HUGE_PAGE) { - return Err(MapToError::ParentEntryHugePage); - } - - let page_table_ptr = next_table_page.start_address().as_mut_ptr(); - let page_table: &mut PageTable = unsafe { &mut *(page_table_ptr) }; - if created { - page_table.zero(); - } - Ok(page_table) - } - - inner(entry, next_table_page, allocator) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_1gib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; - - if !p3[page.p3_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p3[page.p3_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_2mib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; - - let p2_page = p2_page(page, self.recursive_index); - let p2 = unsafe { Self::create_next_table(&mut p3[page.p3_index()], p2_page, allocator)? }; - - if !p2[page.p2_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p2[page.p2_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_4kib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.p4; - - let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; - - let p2_page = p2_page(page, self.recursive_index); - let p2 = unsafe { Self::create_next_table(&mut p3[page.p3_index()], p2_page, allocator)? }; - - let p1_page = p1_page(page, self.recursive_index); - let p1 = unsafe { Self::create_next_table(&mut p2[page.p2_index()], p1_page, allocator)? }; - - if !p1[page.p1_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p1[page.p1_index()].set_frame(frame, flags); - - Ok(MapperFlush::new(page)) - } -} - -impl<'a> Mapper for RecursivePageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_1gib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.p4; - let p4_entry = &p4[page.p4_index()]; - - p4_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &mut p3[page.p3_index()]; - let flags = p3_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p3_entry.addr()))?; - - p3_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - p3[page.p3_index()].set_flags(flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p3_entry.addr())) - } -} - -impl<'a> Mapper for RecursivePageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_2mib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.p4; - let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - p3_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &mut p2[page.p2_index()]; - let flags = p2_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p2_entry.addr()))?; - - p2_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - - if p2[page.p2_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p2[page.p2_index()].set_flags(flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p2 = unsafe { &*(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[page.p2_index()]; - - if p2_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p2_entry.addr())) - } -} - -impl<'a> Mapper for RecursivePageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_4kib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.p4; - let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - p3_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[page.p2_index()]; - p2_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) }; - let p1_entry = &mut p1[page.p1_index()]; - - let frame = p1_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - p1_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - - if p2[page.p2_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) }; - - if p1[page.p1_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p1[page.p1_index()].set_flags(flags); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p2 = unsafe { &*(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[page.p2_index()]; - - if p2_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p1 = unsafe { &*(p1_ptr(page, self.recursive_index)) }; - let p1_entry = &p1[page.p1_index()]; - - if p1_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p1_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p1_entry.addr())) - } -} - -impl<'a> MapperAllSizes for RecursivePageTable<'a> { - fn translate(&self, addr: VirtAddr) -> TranslateResult { - let page = Page::containing_address(addr); - - let p4 = &self.p4; - let p4_entry = &p4[addr.p4_index()]; - if p4_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - panic!("level 4 entry has huge page bit set") - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[addr.p3_index()]; - if p3_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p3_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - let frame = PhysFrame::containing_address(p3[addr.p3_index()].addr()); - let offset = addr.as_usize() & 0o_777_777_7777; - return TranslateResult::Frame1GiB { frame, offset }; - } - - let p2 = unsafe { &*(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[addr.p2_index()]; - if p2_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p2_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - let frame = PhysFrame::containing_address(p2[addr.p2_index()].addr()); - let offset = addr.as_usize() & 0o_777_7777; - return TranslateResult::Frame2MiB { frame, offset }; - } - - let p1 = unsafe { &*(p1_ptr(page, self.recursive_index)) }; - let p1_entry = &p1[addr.p1_index()]; - if p1_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p1_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - panic!("level 1 entry has huge page bit set") - } - - let frame = match PhysFrame::from_start_address(p1_entry.addr()) { - Ok(frame) => frame, - Err(()) => return TranslateResult::InvalidFrameAddress(p1_entry.addr()), - }; - let offset = u64::from(addr.page_offset()) as usize; - TranslateResult::Frame4KiB { frame, offset } - } -} - -fn p3_ptr(page: Page, recursive_index: u9) -> *mut PageTable { - p3_page(page, recursive_index).start_address().as_mut_ptr() -} - -fn p3_page(page: Page, recursive_index: u9) -> Page { - Page::from_page_table_indices( - recursive_index, - recursive_index, - recursive_index, - page.p4_index(), - ) -} - -fn p2_ptr(page: Page, recursive_index: u9) -> *mut PageTable { - p2_page(page, recursive_index).start_address().as_mut_ptr() -} - -fn p2_page(page: Page, recursive_index: u9) -> Page { - Page::from_page_table_indices( - recursive_index, - recursive_index, - page.p4_index(), - page.p3_index(), - ) -} - -fn p1_ptr(page: Page, recursive_index: u9) -> *mut PageTable { - p1_page(page, recursive_index).start_address().as_mut_ptr() -} - -fn p1_page(page: Page, recursive_index: u9) -> Page { - Page::from_page_table_indices( - recursive_index, - page.p4_index(), - page.p3_index(), - page.p2_index(), - ) -} diff --git a/x86_64/src/structures/paging/mod.rs b/x86_64/src/structures/paging/mod.rs deleted file mode 100644 index 5b53829..0000000 --- a/x86_64/src/structures/paging/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Abstractions for page tables and other paging related structures. -//! -//! Page tables translate virtual memory “pages” to physical memory “frames”. - -pub use self::frame::PhysFrame; -pub use self::frame_alloc::{FrameAllocator, FrameDeallocator}; -#[cfg(target_arch = "x86_64")] -#[doc(no_inline)] -pub use self::mapper::{MappedPageTable, OffsetPageTable, RecursivePageTable}; -pub use self::mapper::{Mapper, MapperAllSizes}; -pub use self::page::{Page, PageSize, Size1GiB, Size2MiB, Size4KiB}; -pub use self::page_table::{PageTable, PageTableFlags}; - -pub mod frame; -mod frame_alloc; -pub mod mapper; -pub mod page; -pub mod page_table; diff --git a/x86_64/src/structures/paging/page.rs b/x86_64/src/structures/paging/page.rs deleted file mode 100644 index dc09447..0000000 --- a/x86_64/src/structures/paging/page.rs +++ /dev/null @@ -1,330 +0,0 @@ -//! Abstractions for default-sized and huge virtual memory pages. - -use crate::VirtAddr; -use core::fmt; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Sub, SubAssign}; -use ux::*; - -/// Trait for abstracting over the three possible page sizes on x86_64, 4KiB, 2MiB, 1GiB. -pub trait PageSize: Copy + Eq + PartialOrd + Ord { - /// The page size in bytes. - const SIZE: usize; - - /// A string representation of the page size for debug output. - const SIZE_AS_DEBUG_STR: &'static str; -} - -/// This trait is implemented for 4KiB and 2MiB pages, but not for 1GiB pages. -pub trait NotGiantPageSize: PageSize {} - -/// A standard 4KiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size4KiB {} - -/// A “huge” 2MiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size2MiB {} - -/// A “giant” 1GiB page. -/// -/// (Only available on newer x86_64 CPUs.) -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size1GiB {} - -impl PageSize for Size4KiB { - const SIZE: usize = 4096; - const SIZE_AS_DEBUG_STR: &'static str = "4KiB"; -} - -impl NotGiantPageSize for Size4KiB {} - -impl PageSize for Size2MiB { - const SIZE: usize = Size4KiB::SIZE * 512; - const SIZE_AS_DEBUG_STR: &'static str = "2MiB"; -} - -impl NotGiantPageSize for Size2MiB {} - -impl PageSize for Size1GiB { - const SIZE: usize = Size2MiB::SIZE * 512; - const SIZE_AS_DEBUG_STR: &'static str = "1GiB"; -} - -/// A virtual memory page. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(C)] -pub struct Page { - start_address: VirtAddr, - size: PhantomData, -} - -impl Page { - /// The page size in bytes. - pub const SIZE: usize = S::SIZE; - - /// Returns the page that starts at the given virtual address. - /// - /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start). - pub fn from_start_address(address: VirtAddr) -> Result { - if !address.is_aligned(S::SIZE) { - return Err(()); - } - Ok(Page::containing_address(address)) - } - - /// Returns the page that contains the given virtual address. - pub fn containing_address(address: VirtAddr) -> Self { - Page { - start_address: address.align_down(S::SIZE), - size: PhantomData, - } - } - - /// Returns the start address of the page. - pub fn start_address(&self) -> VirtAddr { - self.start_address - } - - /// Returns the size the page (4KB, 2MB or 1GB). - pub const fn size() -> usize { - S::SIZE - } - - /// Returns the level 4 page table index of this page. - pub fn p4_index(&self) -> u9 { - self.start_address().p4_index() - } - - /// Returns the level 3 page table index of this page. - pub fn p3_index(&self) -> u9 { - self.start_address().p3_index() - } - - /// Returns a range of pages, exclusive `end`. - pub fn range(start: Self, end: Self) -> PageRange { - PageRange { start, end } - } - - /// Returns a range of pages, inclusive `end`. - pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive { - PageRangeInclusive { start, end } - } -} - -impl Page { - /// Returns the level 2 page table index of this page. - pub fn p2_index(&self) -> u9 { - self.start_address().p2_index() - } -} - -impl Page { - /// Returns the 1GiB memory page with the specified page table indices. - pub fn from_page_table_indices_1gib(p4_index: u9, p3_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index) as usize); - addr.set_bits(30..39, u64::from(p3_index) as usize); - Page::containing_address(VirtAddr::new(addr)) - } -} - -impl Page { - /// Returns the 2MiB memory page with the specified page table indices. - pub fn from_page_table_indices_2mib(p4_index: u9, p3_index: u9, p2_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index) as usize); - addr.set_bits(30..39, u64::from(p3_index) as usize); - addr.set_bits(21..30, u64::from(p2_index) as usize); - Page::containing_address(VirtAddr::new(addr)) - } -} - -impl Page { - /// Returns the 4KiB memory page with the specified page table indices. - pub fn from_page_table_indices(p4_index: u9, p3_index: u9, p2_index: u9, p1_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index) as usize); - addr.set_bits(30..39, u64::from(p3_index) as usize); - addr.set_bits(21..30, u64::from(p2_index) as usize); - addr.set_bits(12..21, u64::from(p1_index) as usize); - Page::containing_address(VirtAddr::new(addr)) - } - - /// Returns the level 1 page table index of this page. - pub fn p1_index(&self) -> u9 { - self.start_address().p1_index() - } -} - -impl fmt::Debug for Page { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!( - "Page[{}]({:#x})", - S::SIZE_AS_DEBUG_STR, - self.start_address().as_usize() - )) - } -} - -impl Add for Page { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - Page::containing_address(self.start_address() + rhs * S::SIZE) - } -} - -impl AddAssign for Page { - fn add_assign(&mut self, rhs: usize) { - *self = self.clone() + rhs; - } -} - -impl Sub for Page { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - Page::containing_address(self.start_address() - rhs * S::SIZE) - } -} - -impl SubAssign for Page { - fn sub_assign(&mut self, rhs: usize) { - *self = self.clone() - rhs; - } -} - -impl Sub for Page { - type Output = usize; - fn sub(self, rhs: Self) -> Self::Output { - (self.start_address - rhs.start_address) / S::SIZE - } -} - -/// A range of pages with exclusive upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PageRange { - /// The start of the range, inclusive. - pub start: Page, - /// The end of the range, exclusive. - pub end: Page, -} - -impl PageRange { - /// Returns wether this range contains no pages. - pub fn is_empty(&self) -> bool { - !(self.start < self.end) - } -} - -impl Iterator for PageRange { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start < self.end { - let page = self.start.clone(); - self.start += 1; - Some(page) - } else { - None - } - } -} - -impl PageRange { - /// Converts the range of 2MiB pages to a range of 4KiB pages. - pub fn as_4kib_page_range(self) -> PageRange { - PageRange { - start: Page::containing_address(self.start.start_address()), - end: Page::containing_address(self.end.start_address()), - } - } -} - -impl fmt::Debug for PageRange { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PageRange") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -/// A range of pages with inclusive upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PageRangeInclusive { - /// The start of the range, inclusive. - pub start: Page, - /// The end of the range, inclusive. - pub end: Page, -} - -impl PageRangeInclusive { - /// Returns wether this range contains no pages. - pub fn is_empty(&self) -> bool { - !(self.start <= self.end) - } -} - -impl Iterator for PageRangeInclusive { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let page = self.start.clone(); - self.start += 1; - Some(page) - } else { - None - } - } -} - -impl fmt::Debug for PageRangeInclusive { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PageRangeInclusive") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_page_ranges() { - let page_size = Size4KiB::SIZE; - let number = 1000; - - let start_addr = VirtAddr::new(0xdeadbeaf); - let start: Page = Page::containing_address(start_addr); - let end = start.clone() + number; - - let mut range = Page::range(start.clone(), end.clone()); - for i in 0..number { - assert_eq!( - range.next(), - Some(Page::containing_address(start_addr + page_size * i)) - ); - } - assert_eq!(range.next(), None); - - let mut range_inclusive = Page::range_inclusive(start, end); - for i in 0..=number { - assert_eq!( - range_inclusive.next(), - Some(Page::containing_address(start_addr + page_size * i)) - ); - } - assert_eq!(range_inclusive.next(), None); - } -} diff --git a/x86_64/src/structures/paging/page_table.rs b/x86_64/src/structures/paging/page_table.rs deleted file mode 100644 index 5044eb9..0000000 --- a/x86_64/src/structures/paging/page_table.rs +++ /dev/null @@ -1,236 +0,0 @@ -//! Abstractions for page tables and page table entries. - -use core::fmt; -use core::ops::{Index, IndexMut}; - -use super::{PageSize, PhysFrame, Size4KiB}; -use crate::addr::PhysAddr; - -use bitflags::bitflags; -use ux::*; - -/// The error returned by the `PageTableEntry::frame` method. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum FrameError { - /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame. - FrameNotPresent, - /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame - /// as return type, so a huge frame can't be returned. - HugeFrame, -} - -/// A 64-bit page table entry. -#[derive(Clone)] -#[repr(transparent)] -pub struct PageTableEntry { - entry: u64, -} - -impl PageTableEntry { - /// Creates an unused page table entry. - pub fn new() -> Self { - PageTableEntry { entry: 0 } - } - - /// Returns whether this entry is zero. - pub fn is_unused(&self) -> bool { - self.entry == 0 - } - - /// Sets this entry to zero. - pub fn set_unused(&mut self) { - self.entry = 0; - } - - /// Returns the flags of this entry. - pub fn flags(&self) -> PageTableFlags { - PageTableFlags::from_bits_truncate(self.entry) - } - - /// Returns the physical address mapped by this entry, might be zero. - pub fn addr(&self) -> PhysAddr { - PhysAddr::new(self.entry as usize & 0x000fffff_fffff000) - } - - /// Returns the physical frame mapped by this entry. - /// - /// Returns the following errors: - /// - /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set. - /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the - /// `addr` function must be used) - pub fn frame(&self) -> Result { - if !self.flags().contains(PageTableFlags::PRESENT) { - Err(FrameError::FrameNotPresent) - } else if self.flags().contains(PageTableFlags::HUGE_PAGE) { - Err(FrameError::HugeFrame) - } else { - Ok(PhysFrame::containing_address(self.addr())) - } - } - - /// Map the entry to the specified physical address with the specified flags. - pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) { - assert!(addr.is_aligned(Size4KiB::SIZE)); - self.entry = addr.as_usize() as u64 | flags.bits(); - } - - /// Map the entry to the specified physical frame with the specified flags. - pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) { - assert!(!flags.contains(PageTableFlags::HUGE_PAGE)); - self.set_addr(frame.start_address(), flags) - } - - /// Sets the flags of this entry. - pub fn set_flags(&mut self, flags: PageTableFlags) { - self.entry = self.addr().as_usize() as u64 | flags.bits(); - } -} - -impl fmt::Debug for PageTableEntry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = f.debug_struct("PageTableEntry"); - f.field("addr", &self.addr()); - f.field("flags", &self.flags()); - f.finish() - } -} - -bitflags! { - /// Possible flags for a page table entry. - pub struct PageTableFlags: u64 { - /// Specifies whether the mapped frame or page table is loaded in memory. - const PRESENT = 1 << 0; - /// Controls whether writes to the mapped frames are allowed. - /// - /// If this bit is unset in a level 1 page table entry, the mapped frame is read-only. - /// If this bit is unset in a higher level page table entry the complete range of mapped - /// pages is read-only. - const WRITABLE = 1 << 1; - /// Controls whether accesses from userspace (i.e. ring 3) are permitted. - const USER_ACCESSIBLE = 1 << 2; - /// If this bit is set, a “write-through” policy is used for the cache, else a “write-back” - /// policy is used. - const WRITE_THROUGH = 1 << 3; - /// Disables caching for the pointed entry is cacheable. - const NO_CACHE = 1 << 4; - /// Set by the CPU when the mapped frame or page table is accessed. - const ACCESSED = 1 << 5; - /// Set by the CPU on a write to the mapped frame. - const DIRTY = 1 << 6; - /// Specifies that the entry maps a huge frame instead of a page table. Only allowed in - /// P2 or P3 tables. - const HUGE_PAGE = 1 << 7; - /// Indicates that the mapping is present in all address spaces, so it isn't flushed from - /// the TLB on an address space switch. - const GLOBAL = 1 << 8; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_9 = 1 << 9; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_10 = 1 << 10; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_11 = 1 << 11; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_52 = 1 << 52; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_53 = 1 << 53; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_54 = 1 << 54; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_55 = 1 << 55; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_56 = 1 << 56; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_57 = 1 << 57; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_58 = 1 << 58; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_59 = 1 << 59; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_60 = 1 << 60; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_61 = 1 << 61; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_62 = 1 << 62; - /// Forbid code execution from the mapped frames. - /// - /// Can be only used when the no-execute page protection feature is enabled in the EFER - /// register. - const NO_EXECUTE = 1 << 63; - } -} - -/// The number of entries in a page table. -const ENTRY_COUNT: usize = 512; - -/// Represents a page table. -/// -/// Always page-sized. -/// -/// This struct implements the `Index` and `IndexMut` traits, so the entries can be accessed -/// through index operations. For example, `page_table[15]` returns the 15th page table entry. -#[repr(align(4096))] -#[repr(C)] -pub struct PageTable { - entries: [PageTableEntry; ENTRY_COUNT], -} - -impl PageTable { - /// Creates an empty page table. - pub fn new() -> Self { - PageTable { - entries: unsafe { core::mem::zeroed() }, - } - } - - /// Clears all entries. - pub fn zero(&mut self) { - for entry in self.entries.iter_mut() { - entry.set_unused(); - } - } - - /// Returns an iterator over the entries of the page table. - pub fn iter(&self) -> impl Iterator { - self.entries.iter() - } - - /// Returns an iterator that allows modifying the entries of the page table. - pub fn iter_mut(&mut self) -> impl Iterator { - self.entries.iter_mut() - } -} - -impl Index for PageTable { - type Output = PageTableEntry; - - fn index(&self, index: usize) -> &Self::Output { - &self.entries[index] - } -} - -impl IndexMut for PageTable { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.entries[index] - } -} - -impl Index for PageTable { - type Output = PageTableEntry; - - fn index(&self, index: u9) -> &Self::Output { - &self.entries[cast::usize(u16::from(index))] - } -} - -impl IndexMut for PageTable { - fn index_mut(&mut self, index: u9) -> &mut Self::Output { - &mut self.entries[cast::usize(u16::from(index))] - } -} - -impl fmt::Debug for PageTable { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.entries[..].fmt(f) - } -} diff --git a/x86_64/src/structures/port.rs b/x86_64/src/structures/port.rs deleted file mode 100644 index 925b082..0000000 --- a/x86_64/src/structures/port.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Traits for accessing I/O ports. - -/// A helper trait that implements the read port operation. -/// -/// On x86, I/O ports operate on either `u8` (via `inb`/`outb`), `u16` (via `inw`/`outw`), -/// or `u32` (via `inl`/`outl`). Therefore this trait is implemented for exactly these types. -pub trait PortRead { - /// Reads a `Self` value from the given port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - unsafe fn read_from_port(port: u16) -> Self; -} - -/// A helper trait that implements the write port operation. -/// -/// On x86, I/O ports operate on either `u8` (via `inb`/`outb`), `u16` (via `inw`/`outw`), -/// or `u32` (via `inl`/`outl`). Therefore this trait is implemented for exactly these types. -pub trait PortWrite { - /// Writes a `Self` value to the given port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - unsafe fn write_to_port(port: u16, value: Self); -} - -/// A helper trait that implements the read/write port operations. -/// -/// On x86, I/O ports operate on either `u8` (via `inb`/`outb`), `u16` (via `inw`/`outw`), -/// or `u32` (via `inl`/`outl`). Therefore this trait is implemented for exactly these types. -pub trait PortReadWrite: PortRead + PortWrite {} diff --git a/x86_64/src/structures/tss.rs b/x86_64/src/structures/tss.rs deleted file mode 100644 index 28448d2..0000000 --- a/x86_64/src/structures/tss.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Provides a type for the task state segment structure. - -use crate::VirtAddr; - -/// In 64-bit mode the TSS holds information that is not -/// directly related to the task-switch mechanism, -/// but is used for finding kernel level stack -/// if interrupts arrive while in kernel mode. -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct TaskStateSegment { - reserved_1: u32, - /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2. - pub privilege_stack_table: [VirtAddr; 3], - reserved_2: u64, - /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers. - pub interrupt_stack_table: [VirtAddr; 7], - reserved_3: u64, - reserved_4: u16, - /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base. - pub iomap_base: u16, -} - -impl TaskStateSegment { - /// Creates a new TSS with zeroed privilege and interrupt stack table and a zero - /// `iomap_base`. - pub const fn new() -> TaskStateSegment { - TaskStateSegment { - privilege_stack_table: [VirtAddr::zero(); 3], - interrupt_stack_table: [VirtAddr::zero(); 7], - iomap_base: 0, - reserved_1: 0, - reserved_2: 0, - reserved_3: 0, - reserved_4: 0, - } - } -}