diff --git a/src/Cargo.lock b/src/Cargo.lock index e51e342d..29fda36e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -100,6 +100,7 @@ dependencies = [ "font8x8", "lazy_static", "linked_list_allocator", + "pci", "spin 0.9.4", "uart_16550", "volatile", @@ -168,6 +169,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "pci" +version = "0.0.1" +source = "git+https://github.com/rcore-os/pci-rs#a4e7cea640f8a92ae4b51c6c51fee3f1f0317af2" +dependencies = [ + "bitflags", +] + [[package]] name = "proc-macro2" version = "1.0.43" diff --git a/src/kxos-boot/src/main.rs b/src/kxos-boot/src/main.rs index 97a9738a..7ce7da49 100644 --- a/src/kxos-boot/src/main.rs +++ b/src/kxos-boot/src/main.rs @@ -1,28 +1,24 @@ use anyhow::anyhow; use std::{ + fs::OpenOptions, path::{Path, PathBuf}, process::{Command, ExitStatus}, time::Duration, }; -const RUN_ARGS: &[&str] = &[ +const COMMON_ARGS: &[&str] = &[ "--no-reboot", - "-s", - "-device", - "isa-debug-exit,iobase=0xf4,iosize=0x04", - "-serial", - "stdio", "-display", "none", -]; -const TEST_ARGS: &[&str] = &[ "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", + "-device", + "virtio-blk-pci,bus=pci.0,addr=0x6,drive=x0", "-serial", "stdio", - "-display", - "none", - "--no-reboot", ]; + +const RUN_ARGS: &[&str] = &["-s"]; +const TEST_ARGS: &[&str] = &[]; const TEST_TIMEOUT_SECS: u64 = 10; fn main() -> anyhow::Result<()> { let mut args = std::env::args().skip(1); // skip executable name @@ -53,8 +49,13 @@ fn main() -> anyhow::Result<()> { .arg(format!("format=raw,file={}", bios.display())); let binary_kind = runner_utils::binary_kind(&kernel_binary_path); + let mut args = COMMON_ARGS.clone().to_vec(); + args.push("-drive"); + let binding = create_fs_image(kernel_binary_path.as_path())?; + args.push(binding.as_str()); if binary_kind.is_test() { - run_cmd.args(TEST_ARGS); + args.append(&mut TEST_ARGS.to_vec()); + run_cmd.args(args); let exit_status = run_test_command(run_cmd)?; match exit_status.code() { @@ -62,7 +63,8 @@ fn main() -> anyhow::Result<()> { other => return Err(anyhow!("Test failed (exit code: {:?})", other)), } } else { - run_cmd.args(RUN_ARGS); + args.append(&mut RUN_ARGS.to_vec()); + run_cmd.args(args); let exit_status = run_cmd.status()?; if !exit_status.success() { @@ -72,6 +74,29 @@ fn main() -> anyhow::Result<()> { Ok(()) } +fn create_fs_image(path: &Path) -> anyhow::Result { + let mut fs_img_path = path.parent().unwrap().to_str().unwrap().to_string(); + fs_img_path.push_str("/fs.img"); + let path = Path::new(fs_img_path.as_str()); + if path.exists() { + return Ok(format!( + "file={},if=none,format=raw,id=x0", + fs_img_path.as_str() + )); + } + let f = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(fs_img_path.as_str())?; + // 64MiB + f.set_len(1 * 1024 * 1024).unwrap(); + Ok(format!( + "file={},if=none,format=raw,id=x0", + fs_img_path.as_str() + )) +} + pub fn create_disk_images(kernel_binary_path: &Path) -> PathBuf { let bootloader_manifest_path = bootloader_locator::locate_bootloader("bootloader").unwrap(); let kernel_manifest_path = locate_cargo_manifest::locate_manifest().unwrap(); diff --git a/src/kxos-frame/Cargo.toml b/src/kxos-frame/Cargo.toml index 62659785..64e03045 100644 --- a/src/kxos-frame/Cargo.toml +++ b/src/kxos-frame/Cargo.toml @@ -15,7 +15,7 @@ linked_list_allocator = "0.9.0" bootloader = {version="0.10.12"} font8x8 = { version = "0.2.5", default-features = false, features = ["unicode"]} uart_16550 = "0.2.0" - +pci = { git = "https://github.com/rcore-os/pci-rs" } [dependencies.lazy_static] version = "1.0" diff --git a/src/kxos-frame/src/cpu.rs b/src/kxos-frame/src/cpu.rs index 2cf5076b..2ce619db 100644 --- a/src/kxos-frame/src/cpu.rs +++ b/src/kxos-frame/src/cpu.rs @@ -27,6 +27,16 @@ pub struct CpuContext { pub gp_regs: GpRegs, pub fs_base: u64, pub fp_regs: FpRegs, + pub trap_information: Option, +} +#[derive(Clone, Default, Copy)] +#[repr(C)] +pub struct TrapInformation { + pub cr2: u64, + pub id: u64, + pub err: u64, + pub cs: u64, + pub ss: u64, } /// The general-purpose registers of CPU. @@ -57,27 +67,28 @@ impl From for CpuContext { fn from(syscall: SyscallFrame) -> Self { Self { gp_regs: GpRegs { - r8: syscall.caller.r8 as u64, - r9: syscall.caller.r9 as u64, - r10: syscall.caller.r10 as u64, - r11: syscall.caller.r11 as u64, - r12: syscall.callee.r12 as u64, - r13: syscall.callee.r13 as u64, - r14: syscall.callee.r14 as u64, - r15: syscall.callee.r15 as u64, - rdi: syscall.caller.rdi as u64, - rsi: syscall.caller.rsi as u64, - rbp: syscall.callee.rbp as u64, - rbx: syscall.callee.rbx as u64, - rdx: syscall.caller.rdx as u64, - rax: syscall.caller.rax as u64, - rcx: syscall.caller.rcx as u64, - rsp: syscall.callee.rsp as u64, - rip: syscall.caller.rcx as u64, + r8: syscall.caller.r8, + r9: syscall.caller.r9, + r10: syscall.caller.r10, + r11: syscall.caller.r11, + r12: syscall.callee.r12, + r13: syscall.callee.r13, + r14: syscall.callee.r14, + r15: syscall.callee.r15, + rdi: syscall.caller.rdi, + rsi: syscall.caller.rsi, + rbp: syscall.callee.rbp, + rbx: syscall.callee.rbx, + rdx: syscall.caller.rdx, + rax: syscall.caller.rax, + rcx: syscall.caller.rcx, + rsp: syscall.callee.rsp, + rip: syscall.caller.rcx, rflag: 0, }, fs_base: 0, fp_regs: FpRegs::default(), + trap_information: None, } } } @@ -86,24 +97,24 @@ impl Into for CpuContext { fn into(self) -> SyscallFrame { SyscallFrame { caller: CallerRegs { - rax: self.gp_regs.rax as usize, - rcx: self.gp_regs.rcx as usize, - rdx: self.gp_regs.rdx as usize, - rsi: self.gp_regs.rsi as usize, - rdi: self.gp_regs.rdi as usize, - r8: self.gp_regs.r8 as usize, - r9: self.gp_regs.r9 as usize, - r10: self.gp_regs.r10 as usize, - r11: self.gp_regs.r11 as usize, + rax: self.gp_regs.rax, + rcx: self.gp_regs.rcx, + rdx: self.gp_regs.rdx, + rsi: self.gp_regs.rsi, + rdi: self.gp_regs.rdi, + r8: self.gp_regs.r8, + r9: self.gp_regs.r9, + r10: self.gp_regs.r10, + r11: self.gp_regs.r11, }, callee: CalleeRegs { - rsp: self.gp_regs.rsp as usize, - rbx: self.gp_regs.rbx as usize, - rbp: self.gp_regs.rbp as usize, - r12: self.gp_regs.r12 as usize, - r13: self.gp_regs.r13 as usize, - r14: self.gp_regs.r14 as usize, - r15: self.gp_regs.r15 as usize, + rsp: self.gp_regs.rsp, + rbx: self.gp_regs.rbx, + rbp: self.gp_regs.rbp, + r12: self.gp_regs.r12, + r13: self.gp_regs.r13, + r14: self.gp_regs.r14, + r15: self.gp_regs.r15, }, } } @@ -113,52 +124,70 @@ impl From for CpuContext { fn from(trap: TrapFrame) -> Self { Self { gp_regs: GpRegs { - r8: trap.regs.r8 as u64, - r9: trap.regs.r9 as u64, - r10: trap.regs.r10 as u64, - r11: trap.regs.r11 as u64, - r12: trap.id as u64, - r13: trap.err as u64, - r14: trap.cs as u64, - r15: trap.ss as u64, - rdi: trap.regs.rdi as u64, - rsi: trap.regs.rsi as u64, - rbp: 0 as u64, - rbx: 0 as u64, - rdx: trap.regs.rdx as u64, - rax: trap.regs.rax as u64, - rcx: trap.regs.rcx as u64, - rsp: trap.rsp as u64, - rip: trap.rip as u64, - rflag: trap.rflags as u64, + r8: trap.caller.r8, + r9: trap.caller.r9, + r10: trap.caller.r10, + r11: trap.caller.r11, + r12: trap.callee.r12, + r13: trap.callee.r13, + r14: trap.callee.r14, + r15: trap.callee.r15, + rdi: trap.caller.rdi, + rsi: trap.caller.rsi, + rbp: trap.callee.rbp, + rbx: trap.callee.rbx, + rdx: trap.caller.rdx, + rax: trap.caller.rax, + rcx: trap.caller.rcx, + rsp: trap.rsp, + rip: trap.rip, + rflag: trap.rflags, }, fs_base: 0, fp_regs: FpRegs::default(), + trap_information: Some(TrapInformation { + cr2: trap.cr2, + id: trap.id, + err: trap.err, + cs: trap.cs, + ss: trap.ss, + }), } } } impl Into for CpuContext { fn into(self) -> TrapFrame { + let trap_information = self.trap_information.unwrap(); TrapFrame { - regs: CallerRegs { - rax: self.gp_regs.rax as usize, - rcx: self.gp_regs.rcx as usize, - rdx: self.gp_regs.rdx as usize, - rsi: self.gp_regs.rsi as usize, - rdi: self.gp_regs.rdi as usize, - r8: self.gp_regs.r8 as usize, - r9: self.gp_regs.r9 as usize, - r10: self.gp_regs.r10 as usize, - r11: self.gp_regs.r11 as usize, + caller: CallerRegs { + rax: self.gp_regs.rax, + rcx: self.gp_regs.rcx, + rdx: self.gp_regs.rdx, + rsi: self.gp_regs.rsi, + rdi: self.gp_regs.rdi, + r8: self.gp_regs.r8, + r9: self.gp_regs.r9, + r10: self.gp_regs.r10, + r11: self.gp_regs.r11, }, - id: self.gp_regs.r12 as usize, - err: self.gp_regs.r13 as usize, - rip: self.gp_regs.rip as usize, - cs: self.gp_regs.r14 as usize, - rflags: self.gp_regs.rflag as usize, - rsp: self.gp_regs.rsp as usize, - ss: self.gp_regs.r15 as usize, + callee: CalleeRegs { + rsp: self.gp_regs.rsp, + rbx: self.gp_regs.rbx, + rbp: self.gp_regs.rbp, + r12: self.gp_regs.r12, + r13: self.gp_regs.r13, + r14: self.gp_regs.r14, + r15: self.gp_regs.r15, + }, + id: trap_information.id, + err: trap_information.err, + cr2: trap_information.cr2, + rip: self.gp_regs.rip, + cs: trap_information.cs, + rflags: self.gp_regs.rflag, + rsp: self.gp_regs.rsp, + ss: trap_information.ss, } } } diff --git a/src/kxos-frame/src/drivers/mod.rs b/src/kxos-frame/src/drivers/mod.rs new file mode 100644 index 00000000..8d34b152 --- /dev/null +++ b/src/kxos-frame/src/drivers/mod.rs @@ -0,0 +1,5 @@ +mod pci; + +pub fn init() { + pci::init(); +} diff --git a/src/kxos-frame/src/drivers/pci.rs b/src/kxos-frame/src/drivers/pci.rs new file mode 100644 index 00000000..b9fbadd1 --- /dev/null +++ b/src/kxos-frame/src/drivers/pci.rs @@ -0,0 +1,62 @@ +use crate::*; +use pci::*; + +const PCI_COMMAND: u16 = 0x04; +const PCI_CAP_PTR: u16 = 0x34; +const PCI_INTERRUPT_LINE: u16 = 0x3c; +const PCI_INTERRUPT_PIN: u16 = 0x3d; + +const PCI_MSI_CTRL_CAP: u16 = 0x00; +const PCI_MSI_ADDR: u16 = 0x04; +const PCI_MSI_UPPER_ADDR: u16 = 0x08; +const PCI_MSI_DATA_32: u16 = 0x08; +const PCI_MSI_DATA_64: u16 = 0x0C; + +const PCI_CAP_ID_MSI: u8 = 0x05; + +struct PortOpsImpl; + +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + x86_64_util::in8(port) + } + unsafe fn read16(&self, port: u16) -> u16 { + x86_64_util::in16(port) + } + unsafe fn read32(&self, port: u16) -> u32 { + x86_64_util::in32(port) + } + unsafe fn write8(&self, port: u16, val: u8) { + x86_64_util::out8(port, val); + } + unsafe fn write16(&self, port: u16, val: u16) { + x86_64_util::out16(port, val); + } + unsafe fn write32(&self, port: u16, val: u32) { + x86_64_util::out32(port, val); + } +} + +pub fn init() { + for dev in unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) } { + info!( + "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}", + dev.loc.bus, + dev.loc.device, + dev.loc.function, + dev.id.vendor_id, + dev.id.device_id, + dev.id.class, + dev.id.subclass, + dev.pic_interrupt_line, + dev.interrupt_pin + ); + if dev.id.vendor_id == 0x1af4 + && (dev.id.device_id == 0x1001 || dev.id.device_id == 0x1042) + && dev.id.class == 0x01 + { + // virtio block device mass storage + info!("found virtio pci block device"); + } + } +} diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index ec132f1f..771b7ded 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -16,6 +16,7 @@ pub(crate) mod cell; pub mod config; pub mod cpu; pub mod device; +pub(crate) mod drivers; mod error; pub mod log; pub(crate) mod mm; @@ -75,6 +76,7 @@ pub fn init(boot_info: &'static mut BootInfo) { if !memory_init { panic!("memory init failed"); } + drivers::init(); unsafe { for i in 0..256 { IRQ_CALLBACK_LIST.push(IrqLine::acquire(i as u8).on_active(general_handler)) @@ -82,9 +84,7 @@ pub fn init(boot_info: &'static mut BootInfo) { } } fn general_handler(trap_frame: TrapFrame) { - println!("{:?}", trap_frame); - println!("rip = 0x{:x}", trap_frame.rip); - panic!("couldn't handler trap right now"); + debug!("TrapFrame:{:#x?}", trap_frame); } #[inline(always)] diff --git a/src/kxos-frame/src/task/task.rs b/src/kxos-frame/src/task/task.rs index edc76f51..30c5cf4f 100644 --- a/src/kxos-frame/src/task/task.rs +++ b/src/kxos-frame/src/task/task.rs @@ -69,10 +69,9 @@ lazy_static! { }; task.task_inner.exclusive_access().task_status = TaskStatus::Runnable; task.task_inner.exclusive_access().ctx.rip = context_switch_to_user_space as usize; - task.task_inner.exclusive_access().ctx.regs.rsp = task.kstack.frame.end_pa().unwrap().kvaddr().0 - as usize + task.task_inner.exclusive_access().ctx.regs.rsp = (task.kstack.frame.end_pa().unwrap().kvaddr().0 - size_of::() - - size_of::(); + - size_of::()) as u64; task }); } @@ -172,16 +171,15 @@ impl Task { result.task_inner.exclusive_access().task_status = TaskStatus::Runnable; result.task_inner.exclusive_access().ctx.rip = kernel_task_entry as usize; result.task_inner.exclusive_access().ctx.regs.rsp = - result.kstack.frame.end_pa().unwrap().kvaddr().0 as usize + (result.kstack.frame.end_pa().unwrap().kvaddr().0 - size_of::() - - size_of::(); + - size_of::()) as u64; let arc_self = Arc::new(result); switch_to_task(arc_self.clone()); Ok(arc_self) } - /// create a new task data structure without schedule it pub fn new( task_fn: F, task_data: T, @@ -217,14 +215,13 @@ impl Task { result.task_inner.exclusive_access().task_status = TaskStatus::Runnable; result.task_inner.exclusive_access().ctx.rip = kernel_task_entry as usize; result.task_inner.exclusive_access().ctx.regs.rsp = - result.kstack.frame.end_pa().unwrap().kvaddr().0 as usize + (result.kstack.frame.end_pa().unwrap().kvaddr().0 - size_of::() - - size_of::(); + - size_of::()) as u64; Ok(Arc::new(result)) } - /// send the task to schedule pub fn send_to_scheduler(self: &Arc) { switch_to_task(self.clone()); } diff --git a/src/kxos-frame/src/trap/handler.rs b/src/kxos-frame/src/trap/handler.rs index 7d8e4d0d..d7e30cee 100644 --- a/src/kxos-frame/src/trap/handler.rs +++ b/src/kxos-frame/src/trap/handler.rs @@ -40,7 +40,7 @@ pub(crate) extern "C" fn trap_handler(f: &'static mut TrapFrame) { } } -fn is_from_kernel(cs: usize) -> bool { +fn is_from_kernel(cs: u64) -> bool { if cs & 0x3 == 0 { true } else { diff --git a/src/kxos-frame/src/trap/mod.rs b/src/kxos-frame/src/trap/mod.rs index 5b315e54..113a3b90 100644 --- a/src/kxos-frame/src/trap/mod.rs +++ b/src/kxos-frame/src/trap/mod.rs @@ -12,27 +12,27 @@ core::arch::global_asm!(include_str!("vector.S")); #[derive(Debug, Default, Clone, Copy)] #[repr(C)] pub struct CallerRegs { - pub rax: usize, - pub rcx: usize, - pub rdx: usize, - pub rsi: usize, - pub rdi: usize, - pub r8: usize, - pub r9: usize, - pub r10: usize, - pub r11: usize, + pub rax: u64, + pub rcx: u64, + pub rdx: u64, + pub rsi: u64, + pub rdi: u64, + pub r8: u64, + pub r9: u64, + pub r10: u64, + pub r11: u64, } #[derive(Debug, Default, Clone, Copy)] #[repr(C)] pub struct CalleeRegs { - pub rsp: usize, - pub rbx: usize, - pub rbp: usize, - pub r12: usize, - pub r13: usize, - pub r14: usize, - pub r15: usize, + pub rsp: u64, + pub rbx: u64, + pub rbp: u64, + pub r12: u64, + pub r13: u64, + pub r14: u64, + pub r15: u64, } #[derive(Debug, Default, Clone, Copy)] @@ -45,15 +45,18 @@ pub struct SyscallFrame { #[derive(Debug, Default, Clone, Copy)] #[repr(C)] pub struct TrapFrame { - pub regs: CallerRegs, - pub id: usize, - pub err: usize, + pub cr2: u64, + pub caller: CallerRegs, + // do not use the rsp inside the callee, use another rsp instead + pub callee: CalleeRegs, + pub id: u64, + pub err: u64, // Pushed by CPU - pub rip: usize, - pub cs: usize, - pub rflags: usize, - pub rsp: usize, - pub ss: usize, + pub rip: u64, + pub cs: u64, + pub rflags: u64, + pub rsp: u64, + pub ss: u64, } const TSS_SIZE: usize = 104; diff --git a/src/kxos-frame/src/trap/trap.S b/src/kxos-frame/src/trap/trap.S index 9abf9d2e..f61964f6 100644 --- a/src/kxos-frame/src/trap/trap.S +++ b/src/kxos-frame/src/trap/trap.S @@ -31,20 +31,40 @@ TSS: .global __trap_entry __trap_entry: - # 保存所有的调用者保存寄存器 + # 保存寄存器 + push r15 + push r14 + push r13 + push r12 + push rbp + push rbx + mov rdi, 0 + push rdi save + # save cr2 + mov rdi, cr2 + push rdi # 将栈指针当成参数传入trap_handler mov rdi, rsp call trap_handler __trap_return: # judge whether the trap from kernel mode - mov rax, [rsp + 96] # 96 = offsetof(TrapFrame, cs) + mov rax, [rsp + 160] # 160 = offsetof(TrapFrame, cs) and rax, 0x3 jz __from_kernel - lea rax, [rsp + 128] # prepare new TSS.sp0, 128 = sizeof(TrapFrame) + lea rax, [rsp + 192] # prepare new TSS.sp0, 192 = sizeof(TrapFrame) mov [TSS + rip + 4], rax __from_kernel: + add rsp, 8 # skip cr2 restore + add rsp,8 # skip rsp in callee + pop rbx + pop rbp + pop r12 + pop r13 + pop r14 + pop r15 + add rsp, 16 # skip TrapFrame.err and id iretq @@ -104,4 +124,3 @@ trap_switch_to_user_space: # (cpu_context: *CpuContext,reg: *TrapFrame) jmp __trap_return - diff --git a/src/kxos-frame/src/user.rs b/src/kxos-frame/src/user.rs index 7baad319..1c9cd12a 100644 --- a/src/kxos-frame/src/user.rs +++ b/src/kxos-frame/src/user.rs @@ -114,9 +114,9 @@ impl<'a> UserMode<'a> { self.user_space.vm_space().activate(); } if !self.executed { - self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip as usize; - self.current.syscall_frame().callee.rsp = self.user_space.cpu_ctx.gp_regs.rsp as usize; - self.current.syscall_frame().caller.rax = self.user_space.cpu_ctx.gp_regs.rax as usize; + self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip; + self.current.syscall_frame().callee.rsp = self.user_space.cpu_ctx.gp_regs.rsp; + self.current.syscall_frame().caller.rax = self.user_space.cpu_ctx.gp_regs.rax; self.executed = true; } else { if self.current.inner_exclusive_access().is_from_trap { @@ -144,6 +144,8 @@ impl<'a> UserMode<'a> { self.context = CpuContext::from(*self.current.syscall_frame()); debug!("[kernel] syscall id:{}", self.context.gp_regs.rax); debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); + debug!("[kernel] rcx: 0x{:x}", self.context.gp_regs.rcx); + debug!("[kernel] rip: 0x{:x}", self.context.gp_regs.rip); UserEvent::Syscall } }