Nothing to see here, move along meow
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 22 kB View raw
1use crate::cap::cnode; 2use crate::cap::object::{ObjectTag, PortRange}; 3use crate::cap::ops; 4use crate::cap::pool::POOL; 5use crate::cap::table::Rights; 6use crate::error::KernelError; 7use crate::pci::config::{self, EcamAddress}; 8use crate::pci::{BarInfo, DEVICE_TABLE}; 9use crate::proc::PROCESSES; 10use crate::proc::address_space::map_fb_page_inner; 11use crate::proc::context::CpuContext; 12use crate::syscall::{SyscallResult, try_syscall, validate_user_vaddr}; 13use lancer_core::header::KernelObjectHeader; 14use lancer_core::object_layout::{IrqHandlerObject, KernelObject, PciDeviceObject}; 15 16use x86_64::PhysAddr; 17use x86_64::structures::paging::{PhysFrame, Size4KiB}; 18 19pub fn sys_pci_device_count(ctx: &mut CpuContext) { 20 let table = DEVICE_TABLE.lock(); 21 ctx.rax = SyscallResult::success(table.len() as u64).raw(); 22} 23 24pub fn sys_pci_device_info(ctx: &mut CpuContext) { 25 let cap_addr = ctx.rdi; 26 let buf_ptr = ctx.rsi; 27 let buf_len = try_syscall!(ctx, super::u32_from_reg(ctx.rdx)); 28 29 let pid = crate::arch::syscall::current_pid(); 30 let ptable = PROCESSES.lock(); 31 let cap = { 32 let pool = POOL.lock_after(&ptable); 33 try_syscall!( 34 ctx, 35 cnode::resolve_caller_validate( 36 pid, 37 cap_addr, 38 ObjectTag::PciDevice, 39 Rights::READ, 40 &ptable, 41 &pool 42 ) 43 ) 44 }; 45 drop(ptable); 46 47 let pool = POOL.lock(); 48 let idx = match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) { 49 Ok(d) => d.device_table_idx, 50 Err(e) => { 51 ctx.rax = SyscallResult::error(e).raw(); 52 return; 53 } 54 }; 55 drop(pool); 56 57 let dev_table = DEVICE_TABLE.lock(); 58 let dev = match dev_table.get(idx as usize) { 59 Some(d) => *d, 60 None => { 61 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 62 return; 63 } 64 }; 65 drop(dev_table); 66 67 let wire = dev.to_wire(); 68 let info_bytes = zerocopy::IntoBytes::as_bytes(&wire); 69 70 let copy_len = (buf_len as usize).min(info_bytes.len()); 71 let proof = match crate::sync::InterruptsDisabledToken::new_checked() { 72 Some(tok) => tok, 73 None => { 74 ctx.rax = SyscallResult::error(KernelError::BadState).raw(); 75 return; 76 } 77 }; 78 ctx.rax = match super::copy_to_user(buf_ptr, &info_bytes[..copy_len], copy_len, &proof) { 79 Ok(()) => SyscallResult::success(copy_len as u64).raw(), 80 Err(e) => SyscallResult::error(e).raw(), 81 }; 82} 83 84pub fn sys_pci_config_read32(ctx: &mut CpuContext) { 85 let cap_addr = ctx.rdi; 86 let offset = try_syscall!(ctx, super::u16_from_reg(ctx.rsi)); 87 88 if offset > 0xFFC || offset & 0x3 != 0 { 89 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 90 return; 91 } 92 93 let pid = crate::arch::syscall::current_pid(); 94 let ptable = PROCESSES.lock(); 95 let cap = { 96 let pool = POOL.lock_after(&ptable); 97 try_syscall!( 98 ctx, 99 cnode::resolve_caller_validate( 100 pid, 101 cap_addr, 102 ObjectTag::PciDevice, 103 Rights::READ, 104 &ptable, 105 &pool 106 ) 107 ) 108 }; 109 drop(ptable); 110 111 let pool = POOL.lock(); 112 let idx = match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) { 113 Ok(d) => d.device_table_idx, 114 Err(e) => { 115 ctx.rax = SyscallResult::error(e).raw(); 116 return; 117 } 118 }; 119 drop(pool); 120 121 let dev_table = DEVICE_TABLE.lock(); 122 let dev = match dev_table.get(idx as usize) { 123 Some(d) => *d, 124 None => { 125 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 126 return; 127 } 128 }; 129 drop(dev_table); 130 131 let mcfg_entries = crate::acpi::mcfg::cached_mcfg_entries(); 132 let ecam_base = match mcfg_entries 133 .iter() 134 .find(|e| dev.bus >= e.start_bus && dev.bus <= e.end_bus) 135 { 136 Some(e) => e.base_address, 137 None => { 138 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 139 return; 140 } 141 }; 142 143 let addr = match EcamAddress::new(ecam_base, dev.bus, dev.device, dev.function) { 144 Some(a) => a, 145 None => { 146 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 147 return; 148 } 149 }; 150 let value = config::read_config_u32(addr, offset); 151 ctx.rax = SyscallResult::success(value as u64).raw(); 152} 153 154pub(crate) fn is_config_write_safe(offset: u16, dev: &crate::pci::PciDeviceInfo) -> bool { 155 if matches!(offset, 0x04 | 0x10..=0x27 | 0x30) { 156 return false; 157 } 158 let write_end = offset + 4; 159 dev.blocked_config_ranges 160 .iter() 161 .flatten() 162 .all(|r| offset >= r.end || write_end <= r.start) 163} 164 165pub fn sys_pci_config_write32(ctx: &mut CpuContext) { 166 let cap_addr = ctx.rdi; 167 let offset = try_syscall!(ctx, super::u16_from_reg(ctx.rsi)); 168 let value = try_syscall!(ctx, super::u32_from_reg(ctx.rdx)); 169 170 if offset > 0xFFC || offset & 0x3 != 0 { 171 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 172 return; 173 } 174 175 let pid = crate::arch::syscall::current_pid(); 176 let ptable = PROCESSES.lock(); 177 let cap = { 178 let pool = POOL.lock_after(&ptable); 179 try_syscall!( 180 ctx, 181 cnode::resolve_caller_validate( 182 pid, 183 cap_addr, 184 ObjectTag::PciDevice, 185 Rights::WRITE, 186 &ptable, 187 &pool 188 ) 189 ) 190 }; 191 drop(ptable); 192 193 let pool = POOL.lock(); 194 let idx = match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) { 195 Ok(d) => d.device_table_idx, 196 Err(e) => { 197 ctx.rax = SyscallResult::error(e).raw(); 198 return; 199 } 200 }; 201 drop(pool); 202 203 let dev_table = DEVICE_TABLE.lock(); 204 let dev = match dev_table.get(idx as usize) { 205 Some(d) => *d, 206 None => { 207 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 208 return; 209 } 210 }; 211 drop(dev_table); 212 213 if !is_config_write_safe(offset, &dev) { 214 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw(); 215 return; 216 } 217 218 let mcfg_entries = crate::acpi::mcfg::cached_mcfg_entries(); 219 let ecam_base = match mcfg_entries 220 .iter() 221 .find(|e| dev.bus >= e.start_bus && dev.bus <= e.end_bus) 222 { 223 Some(e) => e.base_address, 224 None => { 225 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 226 return; 227 } 228 }; 229 230 let addr = match EcamAddress::new(ecam_base, dev.bus, dev.device, dev.function) { 231 Some(a) => a, 232 None => { 233 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 234 return; 235 } 236 }; 237 config::write_config_u32(addr, offset, value); 238 ctx.rax = SyscallResult::ok().raw(); 239} 240 241pub fn sys_pci_bar_map(ctx: &mut CpuContext) { 242 let cap_addr = ctx.rdi; 243 let bar_idx = try_syscall!(ctx, super::u8_from_reg(ctx.rsi)); 244 let dest_vaddr = ctx.rdx; 245 let pid = crate::arch::syscall::current_pid(); 246 247 if bar_idx >= 6 { 248 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 249 return; 250 } 251 252 let _ = try_syscall!(ctx, validate_user_vaddr(dest_vaddr)); 253 254 match dest_vaddr & 0xFFF { 255 0 => {} 256 _ => { 257 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw(); 258 return; 259 } 260 } 261 262 let (cap, pml4_phys) = { 263 let ptable = PROCESSES.lock(); 264 let pool = POOL.lock_after(&ptable); 265 match cnode::resolve_caller_validate( 266 pid, 267 cap_addr, 268 ObjectTag::PciDevice, 269 Rights::WRITE, 270 &ptable, 271 &pool, 272 ) { 273 Ok(c) => { 274 let pml4 = ptable 275 .exec(pid) 276 .map(|e| e.pml4_phys) 277 .ok_or(KernelError::InvalidObject); 278 match pml4 { 279 Ok(pml4_phys) => (c, pml4_phys), 280 Err(e) => { 281 ctx.rax = SyscallResult::error(e).raw(); 282 return; 283 } 284 } 285 } 286 Err(e) => { 287 ctx.rax = SyscallResult::error(e).raw(); 288 return; 289 } 290 } 291 }; 292 293 let device_table_idx = { 294 let pool = POOL.lock(); 295 match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) { 296 Ok(d) => d.device_table_idx, 297 Err(e) => { 298 ctx.rax = SyscallResult::error(e).raw(); 299 return; 300 } 301 } 302 }; 303 304 { 305 let bar_mappings = crate::pci::BAR_MAPPINGS.lock(); 306 let already_mapped = bar_mappings 307 .iter() 308 .any(|e| e.matches(pid, device_table_idx, bar_idx)); 309 if already_mapped { 310 ctx.rax = SyscallResult::error(KernelError::BadState).raw(); 311 return; 312 } 313 } 314 315 let dev = { 316 let dev_table = DEVICE_TABLE.lock(); 317 match dev_table.get(device_table_idx as usize) { 318 Some(d) => *d, 319 None => { 320 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 321 return; 322 } 323 } 324 }; 325 326 let (phys_base, size) = match dev.bars[bar_idx as usize] { 327 BarInfo::Memory { 328 phys_base, size, .. 329 } => (phys_base, size), 330 _ => { 331 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 332 return; 333 } 334 }; 335 336 const MAX_BAR_PAGES: usize = 16384; 337 let page_count = size.div_ceil(4096) as usize; 338 339 match page_count > MAX_BAR_PAGES { 340 true => { 341 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 342 return; 343 } 344 false => {} 345 } 346 347 match dest_vaddr.checked_add((page_count as u64) * 4096) { 348 Some(end) if end <= super::USER_ADDR_LIMIT => {} 349 _ => { 350 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw(); 351 return; 352 } 353 } 354 355 let mut allocator = crate::mem::phys::BitmapFrameAllocator; 356 357 let result = (0..page_count).try_fold(0usize, |count, i| { 358 let phys = PhysAddr::new(phys_base + (i as u64) * 4096); 359 let virt = x86_64::VirtAddr::new(dest_vaddr + (i as u64) * 4096); 360 let frame = PhysFrame::<Size4KiB>::containing_address(phys); 361 362 match map_fb_page_inner(pml4_phys, virt, frame, &mut allocator) { 363 Ok(()) => Ok(count + 1), 364 Err(_) => Err((KernelError::ResourceExhausted, count)), 365 } 366 }); 367 368 ctx.rax = match result { 369 Ok(n) => { 370 let entry = crate::pci::BarMappingEntry { 371 pid, 372 device_idx: device_table_idx, 373 bar_idx, 374 base_vaddr: dest_vaddr, 375 }; 376 let _ = crate::pci::BAR_MAPPINGS.lock().push(entry); 377 SyscallResult::success(n as u64).raw() 378 } 379 Err((e, mapped)) => { 380 (0..mapped).for_each(|i| { 381 let virt = x86_64::VirtAddr::new(dest_vaddr + (i as u64) * 4096); 382 let _ = crate::proc::address_space::unmap_user_page(pml4_phys, virt); 383 }); 384 SyscallResult::error(e).raw() 385 } 386 }; 387} 388 389pub fn sys_pci_bar_unmap(ctx: &mut CpuContext) { 390 let cap_addr = ctx.rdi; 391 let bar_idx = try_syscall!(ctx, super::u8_from_reg(ctx.rsi)); 392 let pid = crate::arch::syscall::current_pid(); 393 394 if bar_idx >= 6 { 395 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 396 return; 397 } 398 399 let ptable = PROCESSES.lock(); 400 let (cap, pml4_phys) = { 401 let pool = POOL.lock_after(&ptable); 402 match cnode::resolve_caller_validate( 403 pid, 404 cap_addr, 405 ObjectTag::PciDevice, 406 Rights::WRITE, 407 &ptable, 408 &pool, 409 ) { 410 Ok(c) => { 411 let pml4 = ptable 412 .exec(pid) 413 .map(|e| e.pml4_phys) 414 .ok_or(KernelError::InvalidObject); 415 match pml4 { 416 Ok(pml4_phys) => (c, pml4_phys), 417 Err(e) => { 418 ctx.rax = SyscallResult::error(e).raw(); 419 return; 420 } 421 } 422 } 423 Err(e) => { 424 ctx.rax = SyscallResult::error(e).raw(); 425 return; 426 } 427 } 428 }; 429 430 let device_table_idx = { 431 let pool = POOL.lock_after(&ptable); 432 match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) { 433 Ok(d) => d.device_table_idx, 434 Err(e) => { 435 ctx.rax = SyscallResult::error(e).raw(); 436 return; 437 } 438 } 439 }; 440 drop(ptable); 441 442 let mut bar_mappings = crate::pci::BAR_MAPPINGS.lock(); 443 let mapping_pos = bar_mappings 444 .iter() 445 .enumerate() 446 .find(|(_, e)| e.matches(pid, device_table_idx, bar_idx)) 447 .map(|(i, _)| i); 448 449 let recorded_vaddr = match mapping_pos { 450 Some(pos) => { 451 let vaddr = bar_mappings.get(pos).map(|e| e.base_vaddr).unwrap_or(0); 452 bar_mappings.swap_remove(pos); 453 vaddr 454 } 455 None => { 456 ctx.rax = SyscallResult::error(KernelError::NotFound).raw(); 457 return; 458 } 459 }; 460 drop(bar_mappings); 461 462 let dev_table = DEVICE_TABLE.lock(); 463 let dev = match dev_table.get(device_table_idx as usize) { 464 Some(d) => *d, 465 None => { 466 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 467 return; 468 } 469 }; 470 drop(dev_table); 471 472 let size = match dev.bars[bar_idx as usize] { 473 BarInfo::Memory { size, .. } => size, 474 _ => { 475 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 476 return; 477 } 478 }; 479 480 let page_count = size.div_ceil(4096) as usize; 481 482 (0..page_count).for_each(|i| { 483 let virt = x86_64::VirtAddr::new(recorded_vaddr + (i as u64) * 4096); 484 let _ = crate::proc::address_space::unmap_user_page(pml4_phys, virt); 485 }); 486 487 ctx.rax = SyscallResult::ok().raw(); 488} 489 490pub fn sys_pci_msix_configure(ctx: &mut CpuContext) { 491 let pid = crate::arch::syscall::current_pid(); 492 if pid != crate::types::Pid::new(0) { 493 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw(); 494 return; 495 } 496 497 let pci_cap_addr = ctx.rdi; 498 let entry_idx = try_syscall!(ctx, super::u16_from_reg(ctx.rsi)); 499 let vector = match crate::arch::x86_64::idt::IrqVector::try_new(try_syscall!( 500 ctx, 501 super::u8_from_reg(ctx.rdx) 502 )) { 503 Some(v) => v, 504 None => { 505 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 506 return; 507 } 508 }; 509 let irq_dest_addr = ctx.r10; 510 511 let device_table_idx = { 512 let ptable = PROCESSES.lock(); 513 let pool = POOL.lock_after(&ptable); 514 let pci_cap = try_syscall!( 515 ctx, 516 cnode::resolve_caller_validate( 517 pid, 518 pci_cap_addr, 519 ObjectTag::PciDevice, 520 Rights::WRITE, 521 &ptable, 522 &pool 523 ) 524 ); 525 526 match pool.read_as::<PciDeviceObject>(pci_cap.phys(), pci_cap.generation()) { 527 Ok(d) => d.device_table_idx, 528 Err(e) => { 529 ctx.rax = SyscallResult::error(e).raw(); 530 return; 531 } 532 } 533 }; 534 535 { 536 let dev_table = DEVICE_TABLE.lock(); 537 match dev_table 538 .get(device_table_idx as usize) 539 .and_then(|d| d.msix_cap) 540 { 541 Some(_) => {} 542 None => { 543 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 544 return; 545 } 546 } 547 } 548 549 let hhdm = crate::mem::addr::hhdm_offset(); 550 let boot_pml4 = crate::proc::address_space::boot_pml4_phys(); 551 let mut page_table = unsafe { crate::arch::paging::init_from_phys(boot_pml4, hhdm) }; 552 let mut frame_alloc = crate::mem::phys::BitmapFrameAllocator; 553 554 let map_result = crate::pci::msix::ensure_table_mapped( 555 device_table_idx, 556 &mut page_table, 557 &mut frame_alloc, 558 hhdm, 559 ); 560 if map_result.is_ok() { 561 crate::proc::address_space::sync_kernel_entries(); 562 } 563 let configure_result = map_result 564 .and_then(|()| crate::pci::msix::configure_entry(device_table_idx, entry_idx, vector, 0)) 565 .and_then(|()| crate::pci::msix::enable_msix(device_table_idx)) 566 .and_then(|()| crate::pci::msix::unmask_entry(device_table_idx, entry_idx)); 567 568 match configure_result { 569 Ok(()) => {} 570 Err(e) => { 571 ctx.rax = SyscallResult::error(e).raw(); 572 return; 573 } 574 } 575 576 let _port_range = match PortRange::new(0, 1) { 577 Some(pr) => pr, 578 None => { 579 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 580 return; 581 } 582 }; 583 584 let obj_phys = match crate::cap::kernel_objects::alloc_slot() { 585 Some(p) => p, 586 None => { 587 ctx.rax = SyscallResult::error(KernelError::PoolExhausted).raw(); 588 return; 589 } 590 }; 591 592 let header = KernelObjectHeader::new(ObjectTag::IrqHandler, 0, 64); 593 let mut obj = IrqHandlerObject::init_default(header); 594 obj.vector = vector.raw(); 595 obj.source_kind = 1; 596 obj.source_data = (device_table_idx as u32) | ((entry_idx as u32) << 8); 597 obj.port_base = 0; 598 obj.port_count = 1; 599 crate::cap::kernel_objects::write_at(obj_phys, obj); 600 601 let ptable = PROCESSES.lock(); 602 let (cnode_id, cnode_gen, depth, gv, gb) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); 603 let mut pool = POOL.lock_after(&ptable); 604 605 ctx.rax = match ops::insert_phys_cap_via_cnode( 606 &mut pool, 607 cnode_id, 608 cnode_gen, 609 irq_dest_addr, 610 depth, 611 gv, 612 gb, 613 ObjectTag::IrqHandler, 614 obj_phys, 615 Rights::ALL, 616 ) { 617 Ok(phys) => SyscallResult::success(phys.raw()).raw(), 618 Err(e) => { 619 crate::cap::kernel_objects::free_slot(obj_phys); 620 SyscallResult::error(e).raw() 621 } 622 }; 623} 624 625pub fn sys_pci_create_cap(ctx: &mut CpuContext) { 626 let pid = crate::arch::syscall::current_pid(); 627 if pid != crate::types::Pid::new(0) { 628 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw(); 629 return; 630 } 631 632 let device_table_idx = try_syscall!(ctx, super::u8_from_reg(ctx.rdi)); 633 let dest_addr = ctx.rsi; 634 635 { 636 let dev_table = DEVICE_TABLE.lock(); 637 match dev_table.get(device_table_idx as usize) { 638 Some(_) => {} 639 None => { 640 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 641 return; 642 } 643 } 644 } 645 646 let obj_phys = match crate::cap::kernel_objects::alloc_slot() { 647 Some(p) => p, 648 None => { 649 ctx.rax = SyscallResult::error(KernelError::PoolExhausted).raw(); 650 return; 651 } 652 }; 653 654 let header = KernelObjectHeader::new(ObjectTag::PciDevice, 0, 64); 655 let mut obj = PciDeviceObject::init_default(header); 656 obj.device_table_idx = device_table_idx; 657 crate::cap::kernel_objects::write_at(obj_phys, obj); 658 659 let ptable = PROCESSES.lock(); 660 let (cnode_id, cnode_gen, depth, gv, gb) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); 661 let mut pool = POOL.lock_after(&ptable); 662 663 ctx.rax = match ops::insert_phys_cap_via_cnode( 664 &mut pool, 665 cnode_id, 666 cnode_gen, 667 dest_addr, 668 depth, 669 gv, 670 gb, 671 ObjectTag::PciDevice, 672 obj_phys, 673 Rights::ALL, 674 ) { 675 Ok(_phys) => SyscallResult::ok().raw(), 676 Err(e) => { 677 crate::cap::kernel_objects::free_slot(obj_phys); 678 SyscallResult::error(e).raw() 679 } 680 }; 681} 682 683pub fn sys_pci_enable_bus_master(ctx: &mut CpuContext) { 684 let pid = crate::arch::syscall::current_pid(); 685 if pid != crate::types::Pid::new(0) { 686 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw(); 687 return; 688 } 689 690 let pci_cap_addr = ctx.rdi; 691 692 let device_table_idx = { 693 let ptable = PROCESSES.lock(); 694 let pool = POOL.lock_after(&ptable); 695 let cap = try_syscall!( 696 ctx, 697 cnode::resolve_caller_validate( 698 pid, 699 pci_cap_addr, 700 ObjectTag::PciDevice, 701 Rights::WRITE, 702 &ptable, 703 &pool 704 ) 705 ); 706 match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) { 707 Ok(d) => d.device_table_idx, 708 Err(e) => { 709 ctx.rax = SyscallResult::error(e).raw(); 710 return; 711 } 712 } 713 }; 714 715 ctx.rax = match crate::pci::enable_bus_master(device_table_idx) { 716 Ok(()) => SyscallResult::ok().raw(), 717 Err(e) => SyscallResult::error(e).raw(), 718 }; 719}