140fe15e0SLoGin use core::intrinsics::unlikely; 240fe15e0SLoGin 340fe15e0SLoGin use alloc::sync::Arc; 491e9d4abSLoGin use system_error::SystemError; 540fe15e0SLoGin 6ab5c8ca4Slogin use crate::{ 740fe15e0SLoGin arch::MMArch, 86fc066acSJomo ipc::shm::ShmFlags, 940fe15e0SLoGin kerror, 1040fe15e0SLoGin libs::align::{check_aligned, page_align_up}, 1140fe15e0SLoGin mm::MemoryManagementArch, 1291e9d4abSLoGin syscall::Syscall, 13ab5c8ca4Slogin }; 14ab5c8ca4Slogin 1540fe15e0SLoGin use super::{ 1640fe15e0SLoGin allocator::page_frame::{PageFrameCount, VirtPageFrame}, 1740fe15e0SLoGin ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, 184cfa009bSJomo verify_area, VirtAddr, VmFlags, 1940fe15e0SLoGin }; 2040fe15e0SLoGin 2140fe15e0SLoGin bitflags! { 2240fe15e0SLoGin /// Memory protection flags 2340fe15e0SLoGin pub struct ProtFlags: u64 { 2440fe15e0SLoGin const PROT_NONE = 0x0; 2540fe15e0SLoGin const PROT_READ = 0x1; 2640fe15e0SLoGin const PROT_WRITE = 0x2; 2740fe15e0SLoGin const PROT_EXEC = 0x4; 28ab5c8ca4Slogin } 2940fe15e0SLoGin 3040fe15e0SLoGin /// Memory mapping flags 3140fe15e0SLoGin pub struct MapFlags: u64 { 3240fe15e0SLoGin const MAP_NONE = 0x0; 3340fe15e0SLoGin /// share changes 3440fe15e0SLoGin const MAP_SHARED = 0x1; 3540fe15e0SLoGin /// changes are private 3640fe15e0SLoGin const MAP_PRIVATE = 0x2; 3740fe15e0SLoGin /// Interpret addr exactly 3840fe15e0SLoGin const MAP_FIXED = 0x10; 3940fe15e0SLoGin /// don't use a file 4040fe15e0SLoGin const MAP_ANONYMOUS = 0x20; 4140fe15e0SLoGin // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 4240fe15e0SLoGin /// stack-like segment 4340fe15e0SLoGin const MAP_GROWSDOWN = 0x100; 4440fe15e0SLoGin /// ETXTBSY 4540fe15e0SLoGin const MAP_DENYWRITE = 0x800; 4640fe15e0SLoGin /// Mark it as an executable 4740fe15e0SLoGin const MAP_EXECUTABLE = 0x1000; 4840fe15e0SLoGin /// Pages are locked 4940fe15e0SLoGin const MAP_LOCKED = 0x2000; 5040fe15e0SLoGin /// don't check for reservations 5140fe15e0SLoGin const MAP_NORESERVE = 0x4000; 5240fe15e0SLoGin /// populate (prefault) pagetables 5340fe15e0SLoGin const MAP_POPULATE = 0x8000; 5440fe15e0SLoGin /// do not block on IO 5540fe15e0SLoGin const MAP_NONBLOCK = 0x10000; 5640fe15e0SLoGin /// give out an address that is best suited for process/thread stacks 5740fe15e0SLoGin const MAP_STACK = 0x20000; 5840fe15e0SLoGin /// create a huge page mapping 5940fe15e0SLoGin const MAP_HUGETLB = 0x40000; 6040fe15e0SLoGin /// perform synchronous page faults for the mapping 6140fe15e0SLoGin const MAP_SYNC = 0x80000; 6240fe15e0SLoGin /// MAP_FIXED which doesn't unmap underlying mapping 6340fe15e0SLoGin const MAP_FIXED_NOREPLACE = 0x100000; 6440fe15e0SLoGin 6540fe15e0SLoGin /// For anonymous mmap, memory could be uninitialized 6640fe15e0SLoGin const MAP_UNINITIALIZED = 0x4000000; 674cfa009bSJomo } 6840fe15e0SLoGin 694cfa009bSJomo /// Memory mremapping flags 704cfa009bSJomo pub struct MremapFlags: u8 { 714cfa009bSJomo const MREMAP_MAYMOVE = 1; 724cfa009bSJomo const MREMAP_FIXED = 2; 734cfa009bSJomo const MREMAP_DONTUNMAP = 4; 744cfa009bSJomo } 754cfa009bSJomo } 764cfa009bSJomo 774cfa009bSJomo impl From<MapFlags> for VmFlags { 784cfa009bSJomo fn from(map_flags: MapFlags) -> Self { 794cfa009bSJomo let mut vm_flags = VmFlags::VM_NONE; 804cfa009bSJomo 814cfa009bSJomo if map_flags.contains(MapFlags::MAP_GROWSDOWN) { 824cfa009bSJomo vm_flags |= VmFlags::VM_GROWSDOWN; 834cfa009bSJomo } 844cfa009bSJomo 854cfa009bSJomo if map_flags.contains(MapFlags::MAP_LOCKED) { 864cfa009bSJomo vm_flags |= VmFlags::VM_LOCKED; 874cfa009bSJomo } 884cfa009bSJomo 894cfa009bSJomo if map_flags.contains(MapFlags::MAP_SYNC) { 904cfa009bSJomo vm_flags |= VmFlags::VM_SYNC; 914cfa009bSJomo } 924cfa009bSJomo 934cfa009bSJomo vm_flags 944cfa009bSJomo } 954cfa009bSJomo } 964cfa009bSJomo 974cfa009bSJomo impl From<ProtFlags> for VmFlags { 984cfa009bSJomo fn from(prot_flags: ProtFlags) -> Self { 994cfa009bSJomo let mut vm_flags = VmFlags::VM_NONE; 1004cfa009bSJomo 1014cfa009bSJomo if prot_flags.contains(ProtFlags::PROT_READ) { 1024cfa009bSJomo vm_flags |= VmFlags::VM_READ; 1034cfa009bSJomo } 1044cfa009bSJomo 1054cfa009bSJomo if prot_flags.contains(ProtFlags::PROT_WRITE) { 1064cfa009bSJomo vm_flags |= VmFlags::VM_WRITE; 1074cfa009bSJomo } 1084cfa009bSJomo 1094cfa009bSJomo if prot_flags.contains(ProtFlags::PROT_EXEC) { 1104cfa009bSJomo vm_flags |= VmFlags::VM_EXEC; 1114cfa009bSJomo } 1124cfa009bSJomo 1134cfa009bSJomo vm_flags 1144cfa009bSJomo } 1154cfa009bSJomo } 1164cfa009bSJomo 1176fc066acSJomo impl From<ShmFlags> for VmFlags { 1186fc066acSJomo fn from(shm_flags: ShmFlags) -> Self { 1196fc066acSJomo let mut vm_flags = VmFlags::VM_NONE; 1206fc066acSJomo 1216fc066acSJomo if shm_flags.contains(ShmFlags::SHM_RDONLY) { 1226fc066acSJomo vm_flags |= VmFlags::VM_READ; 1236fc066acSJomo } else { 1246fc066acSJomo vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE; 1256fc066acSJomo } 1266fc066acSJomo 1276fc066acSJomo if shm_flags.contains(ShmFlags::SHM_EXEC) { 1286fc066acSJomo vm_flags |= VmFlags::VM_EXEC; 1296fc066acSJomo } 1306fc066acSJomo 1316fc066acSJomo if shm_flags.contains(ShmFlags::SHM_HUGETLB) { 1326fc066acSJomo vm_flags |= VmFlags::VM_HUGETLB; 1336fc066acSJomo } 1346fc066acSJomo 1356fc066acSJomo vm_flags 1366fc066acSJomo } 1376fc066acSJomo } 1386fc066acSJomo 139b5b571e0SLoGin impl From<VmFlags> for MapFlags { 140b5b571e0SLoGin fn from(value: VmFlags) -> Self { 1414cfa009bSJomo let mut map_flags = MapFlags::MAP_NONE; 1424cfa009bSJomo 143b5b571e0SLoGin if value.contains(VmFlags::VM_GROWSDOWN) { 1444cfa009bSJomo map_flags |= MapFlags::MAP_GROWSDOWN; 1454cfa009bSJomo } 1464cfa009bSJomo 147b5b571e0SLoGin if value.contains(VmFlags::VM_LOCKED) { 1484cfa009bSJomo map_flags |= MapFlags::MAP_LOCKED; 1494cfa009bSJomo } 1504cfa009bSJomo 151b5b571e0SLoGin if value.contains(VmFlags::VM_SYNC) { 1524cfa009bSJomo map_flags |= MapFlags::MAP_SYNC; 1534cfa009bSJomo } 1544cfa009bSJomo 155b5b571e0SLoGin if value.contains(VmFlags::VM_MAYSHARE) { 1563055390cSJomo map_flags |= MapFlags::MAP_SHARED; 1573055390cSJomo } 1583055390cSJomo 1594cfa009bSJomo map_flags 1604cfa009bSJomo } 1614cfa009bSJomo } 1624cfa009bSJomo 163b5b571e0SLoGin impl From<VmFlags> for ProtFlags { 164b5b571e0SLoGin fn from(value: VmFlags) -> Self { 1654cfa009bSJomo let mut prot_flags = ProtFlags::PROT_NONE; 1664cfa009bSJomo 167b5b571e0SLoGin if value.contains(VmFlags::VM_READ) { 1684cfa009bSJomo prot_flags |= ProtFlags::PROT_READ; 1694cfa009bSJomo } 1704cfa009bSJomo 171b5b571e0SLoGin if value.contains(VmFlags::VM_WRITE) { 1724cfa009bSJomo prot_flags |= ProtFlags::PROT_WRITE; 1734cfa009bSJomo } 1744cfa009bSJomo 175b5b571e0SLoGin if value.contains(VmFlags::VM_EXEC) { 1764cfa009bSJomo prot_flags |= ProtFlags::PROT_EXEC; 1774cfa009bSJomo } 1784cfa009bSJomo 1794cfa009bSJomo prot_flags 18040fe15e0SLoGin } 18140fe15e0SLoGin } 18240fe15e0SLoGin 183ab5c8ca4Slogin impl Syscall { 18440fe15e0SLoGin pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> { 18540fe15e0SLoGin // kdebug!("brk: new_addr={:?}", new_addr); 18640fe15e0SLoGin let address_space = AddressSpace::current()?; 18740fe15e0SLoGin let mut address_space = address_space.write(); 18840fe15e0SLoGin 1896d81180bSLoGin if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR { 1906d81180bSLoGin return Ok(address_space.brk); 1916d81180bSLoGin } 1926d81180bSLoGin if new_addr == address_space.brk { 1936d81180bSLoGin return Ok(address_space.brk); 1946d81180bSLoGin } 1956d81180bSLoGin 19640fe15e0SLoGin unsafe { 19740fe15e0SLoGin address_space 19840fe15e0SLoGin .set_brk(VirtAddr::new(page_align_up(new_addr.data()))) 19940fe15e0SLoGin .ok(); 20040fe15e0SLoGin 20140fe15e0SLoGin return Ok(address_space.sbrk(0).unwrap()); 202ab5c8ca4Slogin } 203d8ad0a5eSLoGin } 204d8ad0a5eSLoGin 20540fe15e0SLoGin pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> { 20640fe15e0SLoGin let address_space = AddressSpace::current()?; 2071496ba7bSLoGin assert!(address_space.read().user_mapper.utable.is_current()); 20840fe15e0SLoGin let mut address_space = address_space.write(); 20940fe15e0SLoGin let r = unsafe { address_space.sbrk(incr) }; 21040fe15e0SLoGin 21140fe15e0SLoGin return r; 212d8ad0a5eSLoGin } 213d8ad0a5eSLoGin 21440fe15e0SLoGin /// ## mmap系统调用 215d8ad0a5eSLoGin /// 21640fe15e0SLoGin /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 21740fe15e0SLoGin /// 21840fe15e0SLoGin /// ## 参数 21940fe15e0SLoGin /// 22040fe15e0SLoGin /// - `start_vaddr`:映射的起始地址 22140fe15e0SLoGin /// - `len`:映射的长度 22240fe15e0SLoGin /// - `prot`:保护标志 22340fe15e0SLoGin /// - `flags`:映射标志 22440fe15e0SLoGin /// - `fd`:文件描述符(暂时不支持) 22540fe15e0SLoGin /// - `offset`:文件偏移量 (暂时不支持) 22640fe15e0SLoGin /// 22740fe15e0SLoGin /// ## 返回值 22840fe15e0SLoGin /// 22940fe15e0SLoGin /// 成功时返回映射的起始地址,失败时返回错误码 23040fe15e0SLoGin pub fn mmap( 23140fe15e0SLoGin start_vaddr: VirtAddr, 23240fe15e0SLoGin len: usize, 23340fe15e0SLoGin prot_flags: usize, 23440fe15e0SLoGin map_flags: usize, 23540fe15e0SLoGin _fd: i32, 23640fe15e0SLoGin _offset: usize, 23740fe15e0SLoGin ) -> Result<usize, SystemError> { 23840fe15e0SLoGin let map_flags = MapFlags::from_bits_truncate(map_flags as u64); 23940fe15e0SLoGin let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); 24040fe15e0SLoGin 24140fe15e0SLoGin if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) 24240fe15e0SLoGin && map_flags.contains(MapFlags::MAP_FIXED) 24340fe15e0SLoGin { 24440fe15e0SLoGin kerror!( 24540fe15e0SLoGin "mmap: MAP_FIXED is not supported for address below {}", 24640fe15e0SLoGin DEFAULT_MMAP_MIN_ADDR 24740fe15e0SLoGin ); 24840fe15e0SLoGin return Err(SystemError::EINVAL); 249d8ad0a5eSLoGin } 25040fe15e0SLoGin // 暂时不支持除匿名页以外的映射 25140fe15e0SLoGin if !map_flags.contains(MapFlags::MAP_ANONYMOUS) { 25240fe15e0SLoGin kerror!("mmap: not support file mapping"); 253*1074eb34SSamuel Dai return Err(SystemError::ENOSYS); 25440fe15e0SLoGin } 25540fe15e0SLoGin 25640fe15e0SLoGin // 暂时不支持巨页映射 25740fe15e0SLoGin if map_flags.contains(MapFlags::MAP_HUGETLB) { 25840fe15e0SLoGin kerror!("mmap: not support huge page mapping"); 259*1074eb34SSamuel Dai return Err(SystemError::ENOSYS); 26040fe15e0SLoGin } 26140fe15e0SLoGin let current_address_space = AddressSpace::current()?; 26240fe15e0SLoGin let start_page = current_address_space.write().map_anonymous( 26340fe15e0SLoGin start_vaddr, 26440fe15e0SLoGin len, 26540fe15e0SLoGin prot_flags, 26640fe15e0SLoGin map_flags, 26740fe15e0SLoGin true, 26840fe15e0SLoGin )?; 26940fe15e0SLoGin return Ok(start_page.virt_address().data()); 27040fe15e0SLoGin } 27140fe15e0SLoGin 2724cfa009bSJomo /// ## mremap系统调用 2734cfa009bSJomo /// 2744cfa009bSJomo /// 2754cfa009bSJomo /// ## 参数 2764cfa009bSJomo /// 2774cfa009bSJomo /// - `old_vaddr`:原映射的起始地址 2784cfa009bSJomo /// - `old_len`:原映射的长度 2794cfa009bSJomo /// - `new_len`:重新映射的长度 2804cfa009bSJomo /// - `mremap_flags`:重映射标志 2814cfa009bSJomo /// - `new_vaddr`:重新映射的起始地址 2824cfa009bSJomo /// 2834cfa009bSJomo /// ## 返回值 2844cfa009bSJomo /// 2854cfa009bSJomo /// 成功时返回重映射的起始地址,失败时返回错误码 2864cfa009bSJomo pub fn mremap( 2874cfa009bSJomo old_vaddr: VirtAddr, 2884cfa009bSJomo old_len: usize, 2894cfa009bSJomo new_len: usize, 2904cfa009bSJomo mremap_flags: MremapFlags, 2914cfa009bSJomo new_vaddr: VirtAddr, 2924cfa009bSJomo ) -> Result<usize, SystemError> { 2934cfa009bSJomo // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址 2944cfa009bSJomo if mremap_flags.contains(MremapFlags::MREMAP_FIXED) 2954cfa009bSJomo && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) 2964cfa009bSJomo || new_vaddr == VirtAddr::new(0)) 2974cfa009bSJomo { 2984cfa009bSJomo return Err(SystemError::EINVAL); 2994cfa009bSJomo } 3004cfa009bSJomo 3014cfa009bSJomo // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小 3024cfa009bSJomo if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) 3034cfa009bSJomo && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len) 3044cfa009bSJomo { 3054cfa009bSJomo return Err(SystemError::EINVAL); 3064cfa009bSJomo } 3074cfa009bSJomo 3084cfa009bSJomo // 旧内存地址必须对齐 3094cfa009bSJomo if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) { 3104cfa009bSJomo return Err(SystemError::EINVAL); 3114cfa009bSJomo } 3124cfa009bSJomo 3134cfa009bSJomo // 将old_len、new_len 对齐页面大小 3144cfa009bSJomo let old_len = page_align_up(old_len); 3154cfa009bSJomo let new_len = page_align_up(new_len); 3164cfa009bSJomo 3174cfa009bSJomo // 不允许重映射内存区域大小为0 3184cfa009bSJomo if new_len == 0 { 3194cfa009bSJomo return Err(SystemError::EINVAL); 3204cfa009bSJomo } 3214cfa009bSJomo 3224cfa009bSJomo let current_address_space = AddressSpace::current()?; 3234cfa009bSJomo let vma = current_address_space.read().mappings.contains(old_vaddr); 3244cfa009bSJomo if vma.is_none() { 3254cfa009bSJomo return Err(SystemError::EINVAL); 3264cfa009bSJomo } 3274cfa009bSJomo let vma = vma.unwrap(); 328b5b571e0SLoGin let vm_flags = *vma.lock().vm_flags(); 3294cfa009bSJomo 3304cfa009bSJomo // 暂时不支持巨页映射 3314cfa009bSJomo if vm_flags.contains(VmFlags::VM_HUGETLB) { 3324cfa009bSJomo kerror!("mmap: not support huge page mapping"); 3334cfa009bSJomo return Err(SystemError::ENOSYS); 3344cfa009bSJomo } 3354cfa009bSJomo 3364cfa009bSJomo // 缩小旧内存映射区域 3374cfa009bSJomo if old_len > new_len { 3384cfa009bSJomo Self::munmap(old_vaddr + new_len, old_len - new_len)?; 3394cfa009bSJomo return Ok(old_vaddr.data()); 3404cfa009bSJomo } 3414cfa009bSJomo 3424cfa009bSJomo // 重映射到新内存区域 3434cfa009bSJomo let r = current_address_space.write().mremap( 3444cfa009bSJomo old_vaddr, 3454cfa009bSJomo old_len, 3464cfa009bSJomo new_len, 3474cfa009bSJomo mremap_flags, 3484cfa009bSJomo new_vaddr, 3494cfa009bSJomo vm_flags, 3504cfa009bSJomo )?; 3514cfa009bSJomo 3524cfa009bSJomo if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) { 3534cfa009bSJomo Self::munmap(old_vaddr, old_len)?; 3544cfa009bSJomo } 3554cfa009bSJomo 3564cfa009bSJomo return Ok(r.data()); 3574cfa009bSJomo } 3584cfa009bSJomo 35940fe15e0SLoGin /// ## munmap系统调用 36040fe15e0SLoGin /// 36140fe15e0SLoGin /// ## 参数 36240fe15e0SLoGin /// 36340fe15e0SLoGin /// - `start_vaddr`:取消映射的起始地址(已经对齐到页) 36440fe15e0SLoGin /// - `len`:取消映射的字节数(已经对齐到页) 36540fe15e0SLoGin /// 36640fe15e0SLoGin /// ## 返回值 36740fe15e0SLoGin /// 36840fe15e0SLoGin /// 成功时返回0,失败时返回错误码 36940fe15e0SLoGin pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> { 37040fe15e0SLoGin assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 37140fe15e0SLoGin assert!(check_aligned(len, MMArch::PAGE_SIZE)); 37240fe15e0SLoGin 37340fe15e0SLoGin if unlikely(verify_area(start_vaddr, len).is_err()) { 37440fe15e0SLoGin return Err(SystemError::EINVAL); 37540fe15e0SLoGin } 37640fe15e0SLoGin if unlikely(len == 0) { 37740fe15e0SLoGin return Err(SystemError::EINVAL); 37840fe15e0SLoGin } 37940fe15e0SLoGin 38040fe15e0SLoGin let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 38140fe15e0SLoGin let start_frame = VirtPageFrame::new(start_vaddr); 38240fe15e0SLoGin let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 38340fe15e0SLoGin 38440fe15e0SLoGin current_address_space 38540fe15e0SLoGin .write() 38640fe15e0SLoGin .munmap(start_frame, page_count) 38740fe15e0SLoGin .map_err(|_| SystemError::EINVAL)?; 3884cfa009bSJomo 38940fe15e0SLoGin return Ok(0); 39040fe15e0SLoGin } 39140fe15e0SLoGin 39240fe15e0SLoGin /// ## mprotect系统调用 39340fe15e0SLoGin /// 39440fe15e0SLoGin /// ## 参数 39540fe15e0SLoGin /// 39640fe15e0SLoGin /// - `start_vaddr`:起始地址(已经对齐到页) 39740fe15e0SLoGin /// - `len`:长度(已经对齐到页) 39840fe15e0SLoGin /// - `prot_flags`:保护标志 39940fe15e0SLoGin pub fn mprotect( 40040fe15e0SLoGin start_vaddr: VirtAddr, 40140fe15e0SLoGin len: usize, 40240fe15e0SLoGin prot_flags: usize, 40340fe15e0SLoGin ) -> Result<usize, SystemError> { 40440fe15e0SLoGin assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 40540fe15e0SLoGin assert!(check_aligned(len, MMArch::PAGE_SIZE)); 40640fe15e0SLoGin 40740fe15e0SLoGin if unlikely(verify_area(start_vaddr, len).is_err()) { 40840fe15e0SLoGin return Err(SystemError::EINVAL); 40940fe15e0SLoGin } 41040fe15e0SLoGin if unlikely(len == 0) { 41140fe15e0SLoGin return Err(SystemError::EINVAL); 41240fe15e0SLoGin } 41340fe15e0SLoGin 41440fe15e0SLoGin let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?; 41540fe15e0SLoGin 41640fe15e0SLoGin let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 41740fe15e0SLoGin let start_frame = VirtPageFrame::new(start_vaddr); 41840fe15e0SLoGin let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 41940fe15e0SLoGin 42040fe15e0SLoGin current_address_space 42140fe15e0SLoGin .write() 42240fe15e0SLoGin .mprotect(start_frame, page_count, prot_flags) 42340fe15e0SLoGin .map_err(|_| SystemError::EINVAL)?; 42440fe15e0SLoGin return Ok(0); 425ab5c8ca4Slogin } 426ab5c8ca4Slogin } 427