Nothing to see here, move along
at main 530 lines 17 kB view raw
1pub mod boot_info; 2pub mod cap; 3pub mod clock; 4pub mod cnode; 5pub mod debug; 6#[cfg(lancer_test)] 7pub mod debug_info; 8pub mod dma; 9pub mod exit; 10pub mod fb; 11pub mod frame; 12pub mod iommu; 13pub mod ipc; 14pub mod irq; 15pub mod log; 16pub mod module; 17pub mod notify; 18pub mod pci; 19pub mod platform; 20pub mod proc; 21pub mod retype; 22pub mod ring; 23pub mod sched; 24pub mod vregion; 25 26use crate::error::KernelError; 27use crate::proc::context::CpuContext; 28use crate::types::{MAX_PIDS, Pid}; 29 30#[repr(transparent)] 31#[derive(Debug, Clone, Copy)] 32pub struct SyscallResult(u64); 33 34impl SyscallResult { 35 pub const fn success(val: u64) -> Self { 36 debug_assert!( 37 (val as i64) >= 0, 38 "SyscallResult::success value collides with errno range" 39 ); 40 Self(val) 41 } 42 43 pub const fn ok() -> Self { 44 Self(0) 45 } 46 47 pub const fn error(e: KernelError) -> Self { 48 Self(e.to_errno() as u64) 49 } 50 51 #[allow(dead_code)] 52 pub const fn is_err(self) -> bool { 53 (self.0 as i64) < 0 54 } 55 56 pub const fn raw(self) -> u64 { 57 self.0 58 } 59} 60 61impl From<KernelError> for SyscallResult { 62 fn from(e: KernelError) -> Self { 63 Self::error(e) 64 } 65} 66 67impl<T> From<Result<T, KernelError>> for SyscallResult 68where 69 T: Into<SyscallResult>, 70{ 71 fn from(r: Result<T, KernelError>) -> Self { 72 match r { 73 Ok(v) => v.into(), 74 Err(e) => Self::error(e), 75 } 76 } 77} 78 79macro_rules! try_syscall { 80 ($ctx:expr, $expr:expr) => { 81 match $expr { 82 Ok(val) => val, 83 Err(e) => { 84 $ctx.rax = SyscallResult::error(e).raw(); 85 return; 86 } 87 } 88 }; 89} 90 91pub(crate) use try_syscall; 92 93macro_rules! syscall_enum { 94 ($( $name:ident = $val:expr ),+ $(,)?) => { 95 #[repr(u64)] 96 #[derive(Debug, Clone, Copy)] 97 pub enum SyscallNr { 98 $( $name = $val ),+ 99 } 100 101 impl TryFrom<u64> for SyscallNr { 102 type Error = (); 103 fn try_from(nr: u64) -> Result<Self, ()> { 104 match nr { 105 $( $val => Ok(Self::$name), )+ 106 _ => Err(()), 107 } 108 } 109 } 110 }; 111} 112 113syscall_enum! { 114 Nop = 0, 115 DebugPrint = 1, 116 Exit = 2, 117 Getpid = 3, 118 SysLog = 4, 119 GetProcName = 5, 120 121 CapDerive = 11, 122 CapRevoke = 12, 123 CapIdentify = 13, 124 CapGrant = 14, 125 126 CnodeCreate = 15, 127 CnodeCopy = 16, 128 CnodeDelete = 17, 129 CnodeMint = 18, 130 CnodeCopyTo = 19, 131 132 Send = 20, 133 Recv = 21, 134 Call = 22, 135 ReplyRecv = 23, 136 NbRecv = 24, 137 138 NotifySignal = 30, 139 NotifyWait = 31, 140 NotifyPoll = 32, 141 NtfnBind = 33, 142 NtfnUnbind = 34, 143 144 FrameMap = 44, 145 FrameUnmap = 45, 146 FrameMapChild = 46, 147 148 RingRegister = 50, 149 RingEnter = 51, 150 151 SchedAttach = 61, 152 SchedYield = 62, 153 SchedConfigure = 63, 154 155 ProcCreate = 70, 156 ProcSetRegs = 72, 157 ProcStart = 73, 158 ProcDestroy = 74, 159 ProcLoadModule = 75, 160 ProcBindDeathNotif = 76, 161 ThreadCreate = 77, 162 SetFsBase = 78, 163 GetFsBase = 79, 164 CspaceSetGuard = 84, 165 166 IrqBind = 80, 167 IrqAck = 81, 168 IoIn8 = 82, 169 IoOut8 = 83, 170 IrqConfigure = 85, 171 172 ModuleInfo = 90, 173 FbInfo = 91, 174 FbMap = 92, 175 176 PciDeviceCount = 100, 177 PciDeviceInfo = 101, 178 PciBarMap = 102, 179 PciBarUnmap = 103, 180 PciConfigRead32 = 104, 181 PciConfigWrite32 = 105, 182 PciMsixConfigure = 106, 183 184 ClockMonotonicMs = 110, 185 186 DmaAlloc = 120, 187 DmaFree = 121, 188 IommuMap = 122, 189 IommuUnmap = 123, 190 191 BlackboxRead = 130, 192 193 UntypedRetype = 140, 194 BootUntypedInfo = 141, 195 196 PlatformInfo = 150, 197 PciCreateCap = 151, 198 FbCreateCap = 152, 199 PciEnableBusMaster = 153, 200 IommuSetupDevice = 154, 201 ConsoleRingCreateCap = 155, 202 203 DebugInfo = 160, 204 205 VregionCreate = 170, 206 VregionDestroy = 171, 207} 208 209pub use crate::mem::typed_addr::{MIN_USER_VADDR, USER_ADDR_LIMIT, UserVirtAddr}; 210 211const PAGE_SIZE: u64 = 4096; 212const PT_INDEX_MASK: u64 = 0x1FF; 213const PTE_ADDR_MASK: u64 = 0x000F_FFFF_FFFF_F000; 214const PTE_PRESENT: u64 = 1 << 0; 215const PTE_WRITABLE: u64 = 1 << 1; 216const PTE_USER: u64 = 1 << 2; 217const PTE_HUGE: u64 = 1 << 7; 218const PTE_NX: u64 = 1 << 63; 219const PTE_SIZE: u64 = 8; 220 221fn read_pte(table_phys: u64, index: u64, hhdm: u64) -> u64 { 222 unsafe { core::ptr::read_volatile((table_phys + hhdm + index * PTE_SIZE) as *const u64) } 223} 224 225const L4_SHIFT: u32 = 39; 226const L3_SHIFT: u32 = 30; 227const L2_SHIFT: u32 = 21; 228const L1_SHIFT: u32 = 12; 229const HUGE_1G_OFFSET_MASK: u64 = (1 << L3_SHIFT) - 1; 230const HUGE_2M_OFFSET_MASK: u64 = (1 << L2_SHIFT) - 1; 231 232pub(crate) fn resolve_user_page( 233 pml4_phys: x86_64::PhysAddr, 234 vaddr: u64, 235 needs_write: bool, 236 needs_execute: bool, 237) -> Option<u64> { 238 let hhdm = crate::mem::addr::hhdm_offset(); 239 let required_bits: u64 = if needs_write { 240 PTE_PRESENT | PTE_WRITABLE | PTE_USER 241 } else { 242 PTE_PRESENT | PTE_USER 243 }; 244 let indices: [u64; 4] = [ 245 (vaddr >> L4_SHIFT) & PT_INDEX_MASK, 246 (vaddr >> L3_SHIFT) & PT_INDEX_MASK, 247 (vaddr >> L2_SHIFT) & PT_INDEX_MASK, 248 (vaddr >> L1_SHIFT) & PT_INDEX_MASK, 249 ]; 250 251 #[derive(Clone, Copy)] 252 enum Walk { 253 Next(u64), 254 Huge(u64, u8), 255 Fault, 256 } 257 258 let result = 259 indices 260 .iter() 261 .enumerate() 262 .fold( 263 Walk::Next(pml4_phys.as_u64()), 264 |state, (level, &idx)| match state { 265 Walk::Next(table_phys) => { 266 let entry = read_pte(table_phys, idx, hhdm); 267 if (entry & required_bits != required_bits) 268 || (needs_execute && (entry & PTE_NX) != 0) 269 { 270 Walk::Fault 271 } else if level > 0 && level < 3 && (entry & PTE_HUGE) != 0 { 272 Walk::Huge(entry & PTE_ADDR_MASK, level as u8) 273 } else { 274 Walk::Next(entry & PTE_ADDR_MASK) 275 } 276 } 277 other => other, 278 }, 279 ); 280 281 match result { 282 Walk::Next(frame_phys) => Some(frame_phys), 283 Walk::Huge(base_phys, level) => { 284 let offset_within = match level { 285 1 => vaddr & HUGE_1G_OFFSET_MASK, 286 _ => vaddr & HUGE_2M_OFFSET_MASK, 287 }; 288 Some((base_phys + offset_within) & !0xFFF) 289 } 290 Walk::Fault => None, 291 } 292} 293 294struct PageChunk { 295 frame_offset: u64, 296 len: usize, 297} 298 299fn intersect_page(range_start: u64, range_end: u64, page_base: u64) -> PageChunk { 300 let chunk_start = range_start.max(page_base); 301 let chunk_end = range_end.min(page_base + PAGE_SIZE); 302 PageChunk { 303 frame_offset: chunk_start - page_base, 304 len: (chunk_end - chunk_start) as usize, 305 } 306} 307 308pub fn copy_from_user( 309 src: u64, 310 dst: &mut [u8], 311 len: usize, 312 _proof: &crate::sync::InterruptsDisabledToken, 313) -> Result<(), KernelError> { 314 if len == 0 { 315 return Ok(()); 316 } 317 if len > dst.len() || src < MIN_USER_VADDR { 318 return Err(KernelError::InvalidAddress); 319 } 320 let end = src 321 .checked_add(len as u64) 322 .ok_or(KernelError::InvalidAddress)?; 323 if end >= USER_ADDR_LIMIT { 324 return Err(KernelError::InvalidAddress); 325 } 326 327 let pid = crate::arch::syscall::current_pid(); 328 let pml4 = { 329 let ptable = crate::proc::PROCESSES.lock(); 330 ptable 331 .exec(pid) 332 .map(|e| e.pml4_phys.raw()) 333 .ok_or(KernelError::InvalidObject)? 334 }; 335 336 let hhdm = crate::mem::addr::hhdm_offset(); 337 let max_phys = (crate::mem::phys::BitmapFrameAllocator::total_frames() as u64) * PAGE_SIZE; 338 let start_page = src / PAGE_SIZE; 339 let end_page = (end - 1) / PAGE_SIZE; 340 (start_page..=end_page).try_fold(0usize, |copied, page| { 341 let page_base = page * PAGE_SIZE; 342 let frame_phys = resolve_user_page(pml4, page_base, false, false) 343 .filter(|&fp| fp < max_phys) 344 .ok_or(KernelError::InvalidAddress)?; 345 let chunk = intersect_page(src, end, page_base); 346 let hhdm_src = (frame_phys + hhdm + chunk.frame_offset) as *const u8; 347 unsafe { 348 core::ptr::copy_nonoverlapping(hhdm_src, dst.as_mut_ptr().add(copied), chunk.len); 349 } 350 Ok(copied + chunk.len) 351 })?; 352 Ok(()) 353} 354 355#[allow(dead_code)] 356pub fn copy_to_user( 357 dst: u64, 358 src: &[u8], 359 len: usize, 360 _proof: &crate::sync::InterruptsDisabledToken, 361) -> Result<(), KernelError> { 362 if len == 0 { 363 return Ok(()); 364 } 365 if len > src.len() || dst < MIN_USER_VADDR { 366 return Err(KernelError::InvalidAddress); 367 } 368 let end = dst 369 .checked_add(len as u64) 370 .ok_or(KernelError::InvalidAddress)?; 371 if end >= USER_ADDR_LIMIT { 372 return Err(KernelError::InvalidAddress); 373 } 374 375 let pid = crate::arch::syscall::current_pid(); 376 let pml4 = { 377 let ptable = crate::proc::PROCESSES.lock(); 378 ptable 379 .exec(pid) 380 .map(|e| e.pml4_phys.raw()) 381 .ok_or(KernelError::InvalidObject)? 382 }; 383 384 let hhdm = crate::mem::addr::hhdm_offset(); 385 let max_phys = (crate::mem::phys::BitmapFrameAllocator::total_frames() as u64) * PAGE_SIZE; 386 let start_page = dst / PAGE_SIZE; 387 let end_page = (end - 1) / PAGE_SIZE; 388 (start_page..=end_page).try_fold(0usize, |copied, page| { 389 let page_base = page * PAGE_SIZE; 390 let frame_phys = resolve_user_page(pml4, page_base, true, false) 391 .filter(|&fp| fp < max_phys) 392 .ok_or(KernelError::InvalidAddress)?; 393 let chunk = intersect_page(dst, end, page_base); 394 let hhdm_dst = (frame_phys + hhdm + chunk.frame_offset) as *mut u8; 395 unsafe { 396 core::ptr::copy_nonoverlapping(src.as_ptr().add(copied), hhdm_dst, chunk.len); 397 } 398 Ok(copied + chunk.len) 399 })?; 400 Ok(()) 401} 402 403pub fn validate_user_vaddr(addr: u64) -> Result<UserVirtAddr, KernelError> { 404 UserVirtAddr::new(addr) 405} 406 407pub fn u8_from_reg(val: u64) -> Result<u8, KernelError> { 408 u8::try_from(val).map_err(|_| KernelError::InvalidParameter) 409} 410 411pub fn u16_from_reg(val: u64) -> Result<u16, KernelError> { 412 u16::try_from(val).map_err(|_| KernelError::InvalidParameter) 413} 414 415pub fn u32_from_reg(val: u64) -> Result<u32, KernelError> { 416 u32::try_from(val).map_err(|_| KernelError::InvalidParameter) 417} 418 419#[allow(dead_code)] 420pub fn pid_from_u64(val: u64) -> Result<Pid, KernelError> { 421 if val < MAX_PIDS as u64 { 422 Ok(Pid::new(val as u32)) 423 } else { 424 Err(KernelError::InvalidParameter) 425 } 426} 427 428#[unsafe(no_mangle)] 429pub extern "C" fn syscall_dispatch(ctx: *mut CpuContext, nr: u64) { 430 let ctx = unsafe { &mut *ctx }; 431 let pc = unsafe { &mut *crate::arch::syscall::this_cpu() }; 432 pc.syscall_count += 1; 433 let count = pc.syscall_count; 434 435 match SyscallNr::try_from(nr) { 436 Ok(SyscallNr::Nop) => { 437 if count < 5 { 438 crate::show!(sys, "nop from ring 3 count {}", count); 439 } 440 ctx.rax = 0; 441 } 442 Ok(SyscallNr::DebugPrint) => debug::sys_debug_print(ctx), 443 Ok(SyscallNr::Exit) => exit::sys_exit(ctx), 444 Ok(SyscallNr::SysLog) => log::sys_log(ctx), 445 Ok(SyscallNr::GetProcName) => log::sys_get_proc_name(ctx), 446 Ok(SyscallNr::Getpid) => { 447 ctx.rax = crate::arch::syscall::current_pid().raw() as u64; 448 } 449 Ok(SyscallNr::CapDerive) => cap::sys_cap_derive(ctx), 450 Ok(SyscallNr::CapRevoke) => cap::sys_cap_revoke(ctx), 451 Ok(SyscallNr::CapIdentify) => cap::sys_cap_identify(ctx), 452 Ok(SyscallNr::CapGrant) => cap::sys_cap_grant(ctx), 453 Ok(SyscallNr::CnodeCreate) => cnode::sys_cnode_create(ctx), 454 Ok(SyscallNr::CnodeCopy) => cnode::sys_cnode_copy(ctx), 455 Ok(SyscallNr::CnodeDelete) => cnode::sys_cnode_delete(ctx), 456 Ok(SyscallNr::CnodeMint) => cnode::sys_cnode_mint(ctx), 457 Ok(SyscallNr::CnodeCopyTo) => cnode::sys_cnode_copy_to(ctx), 458 Ok(SyscallNr::Send) => ipc::sys_send(ctx), 459 Ok(SyscallNr::Recv) => ipc::sys_recv(ctx), 460 Ok(SyscallNr::NbRecv) => ipc::sys_nb_recv(ctx), 461 Ok(SyscallNr::Call) => ipc::sys_call(ctx), 462 Ok(SyscallNr::ReplyRecv) => ipc::sys_reply_recv(ctx), 463 Ok(SyscallNr::NotifySignal) => notify::sys_notify_signal(ctx), 464 Ok(SyscallNr::NotifyWait) => notify::sys_notify_wait(ctx), 465 Ok(SyscallNr::NotifyPoll) => notify::sys_notify_poll(ctx), 466 Ok(SyscallNr::NtfnBind) => notify::sys_ntfn_bind(ctx), 467 Ok(SyscallNr::NtfnUnbind) => notify::sys_ntfn_unbind(ctx), 468 Ok(SyscallNr::FrameMap) => frame::sys_frame_map(ctx), 469 Ok(SyscallNr::FrameUnmap) => frame::sys_frame_unmap(ctx), 470 Ok(SyscallNr::FrameMapChild) => frame::sys_frame_map_child(ctx), 471 Ok(SyscallNr::RingRegister) => ring::sys_ring_register(ctx), 472 Ok(SyscallNr::RingEnter) => ring::sys_ring_enter(ctx), 473 Ok(SyscallNr::SchedAttach) => sched::sys_sched_attach(ctx), 474 Ok(SyscallNr::SchedYield) => sched::sys_sched_yield(ctx), 475 Ok(SyscallNr::SchedConfigure) => sched::sys_sched_configure(ctx), 476 Ok(SyscallNr::ProcCreate) => proc::sys_proc_create(ctx), 477 Ok(SyscallNr::ProcSetRegs) => proc::sys_proc_set_regs(ctx), 478 Ok(SyscallNr::ProcStart) => proc::sys_proc_start(ctx), 479 Ok(SyscallNr::ProcDestroy) => proc::sys_proc_destroy(ctx), 480 Ok(SyscallNr::ProcLoadModule) => proc::sys_proc_load_module(ctx), 481 Ok(SyscallNr::ProcBindDeathNotif) => proc::sys_proc_bind_death_notif(ctx), 482 Ok(SyscallNr::ThreadCreate) => proc::sys_thread_create(ctx), 483 Ok(SyscallNr::SetFsBase) => proc::sys_set_fsbase(ctx), 484 Ok(SyscallNr::GetFsBase) => proc::sys_get_fsbase(ctx), 485 Ok(SyscallNr::CspaceSetGuard) => cnode::sys_cspace_set_guard(ctx), 486 Ok(SyscallNr::IrqBind) => irq::sys_irq_bind(ctx), 487 Ok(SyscallNr::IrqAck) => irq::sys_irq_ack(ctx), 488 Ok(SyscallNr::IoIn8) => irq::sys_io_in8(ctx), 489 Ok(SyscallNr::IoOut8) => irq::sys_io_out8(ctx), 490 Ok(SyscallNr::IrqConfigure) => irq::sys_irq_configure(ctx), 491 Ok(SyscallNr::ModuleInfo) => module::sys_module_info(ctx), 492 Ok(SyscallNr::FbInfo) => fb::sys_fb_info(ctx), 493 Ok(SyscallNr::FbMap) => fb::sys_fb_map(ctx), 494 Ok(SyscallNr::PciDeviceCount) => pci::sys_pci_device_count(ctx), 495 Ok(SyscallNr::PciDeviceInfo) => pci::sys_pci_device_info(ctx), 496 Ok(SyscallNr::PciBarMap) => pci::sys_pci_bar_map(ctx), 497 Ok(SyscallNr::PciBarUnmap) => pci::sys_pci_bar_unmap(ctx), 498 Ok(SyscallNr::PciConfigRead32) => pci::sys_pci_config_read32(ctx), 499 Ok(SyscallNr::PciConfigWrite32) => pci::sys_pci_config_write32(ctx), 500 Ok(SyscallNr::PciMsixConfigure) => pci::sys_pci_msix_configure(ctx), 501 Ok(SyscallNr::ClockMonotonicMs) => clock::sys_clock_monotonic_ms(ctx), 502 Ok(SyscallNr::DmaAlloc) => dma::sys_dma_alloc(ctx), 503 Ok(SyscallNr::DmaFree) => dma::sys_dma_free(ctx), 504 Ok(SyscallNr::IommuMap) => iommu::sys_iommu_map(ctx), 505 Ok(SyscallNr::IommuUnmap) => iommu::sys_iommu_unmap(ctx), 506 Ok(SyscallNr::BlackboxRead) => log::sys_blackbox_read(ctx), 507 Ok(SyscallNr::UntypedRetype) => retype::sys_untyped_retype(ctx), 508 Ok(SyscallNr::BootUntypedInfo) => boot_info::sys_boot_untyped_info(ctx), 509 Ok(SyscallNr::PlatformInfo) => platform::sys_platform_info(ctx), 510 Ok(SyscallNr::PciCreateCap) => pci::sys_pci_create_cap(ctx), 511 Ok(SyscallNr::FbCreateCap) => fb::sys_fb_create_cap(ctx), 512 Ok(SyscallNr::PciEnableBusMaster) => pci::sys_pci_enable_bus_master(ctx), 513 Ok(SyscallNr::IommuSetupDevice) => iommu::sys_iommu_setup_device(ctx), 514 Ok(SyscallNr::ConsoleRingCreateCap) => fb::sys_console_ring_create_cap(ctx), 515 Ok(SyscallNr::VregionCreate) => vregion::sys_vregion_create(ctx), 516 Ok(SyscallNr::VregionDestroy) => vregion::sys_vregion_destroy(ctx), 517 Ok(SyscallNr::DebugInfo) => { 518 #[cfg(lancer_test)] 519 debug_info::sys_debug_info(ctx); 520 #[cfg(not(lancer_test))] 521 { 522 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 523 } 524 } 525 Err(()) => { 526 crate::show!(sys, warn, "unknown syscall nr {}", nr); 527 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 528 } 529 } 530}