kernel/lib/types/
user_slice.rs1use crate::arch;
7use crate::lib::panic::kernel_panic;
8use crate::lib::panic_codes::PanicCode;
9use crate::lib::types::fmt_buffer::FmtBuffer;
10use crate::mm::layout::USER_MAX;
11use crate::syscall::result::{SyscallError, SyscallResult};
12
13#[derive(Copy, Clone, Debug)]
15pub struct UserSlice {
16 address: u64,
17 length: u64
18}
19
20impl UserSlice {
21 pub fn new(address: u64, length: u64) -> SyscallResult<Self> {
29 let Some(end) = address.checked_add(length) else {
30 return Err(SyscallError::BadAddress)
31 };
32 if end > USER_MAX {
33 return Err(SyscallError::BadAddress)
34 }
35
36 Ok(Self {
37 address,
38 length
39 })
40 }
41
42 pub fn len(&self) -> u64 {
44 self.length
45 }
46
47 pub fn is_empty(&self) -> bool {
49 self.length == 0
50 }
51
52 pub fn copy_to_slice(&self, slice: &mut [u8]) -> SyscallResult<()> {
58 #[cfg(feature = "debug-checks")]
59 if self.length != slice.len() as u64 {
60 self.incorrect_size_panic(slice.len(), self.length);
61 }
62
63 match self.partial_copy_to_slice(slice, 0, self.length) {
64 0 => Ok(()),
65 _ => Err(SyscallError::BadAddress),
66 }
67 }
68
69 #[must_use]
80 pub fn partial_copy_to_slice(&self, slice: &mut [u8], offset: u64, length: u64) -> u64 {
81 let Some(end) = offset.checked_add(length) else {
82 kernel_panic(
83 PanicCode::InternalKernelError,
84 "UserSlice: adding offset and length overflowed"
85 );
86 };
87
88 if end > self.length {
89 kernel_panic(
90 PanicCode::InternalKernelError,
91 "UserSlice: requested range exceeds slice bounds"
92 );
93 }
94 if length > slice.len() as u64 {
95 self.incorrect_size_panic(slice.len(), length);
96 }
97
98 if length == 0 {
99 return 0;
100 }
101
102 #[cfg(feature = "debug-checks")]
103 if self.address.checked_add(offset).is_none() {
104 kernel_panic(
105 PanicCode::InternalKernelError,
106 "UserSlice: adding address and offset overflowed"
107 );
108 }
109 let start_addr = self.address.wrapping_add(offset);
110
111 unsafe {
115 #[cfg(target_arch = "x86_64")]
116 return arch::x86_64::lib::types::user_slice::partial_copy_to_slice_asm(slice, start_addr, length);
117
118 #[cfg(target_arch = "aarch64")]
119 compile_error!("not implemented")
120 }
121 }
122
123 #[cold]
125 #[inline(never)]
126 fn incorrect_size_panic(&self, dst_len: usize, src_len: u64) -> ! {
127 use core::fmt::Write;
128
129 let mut fmt_buffer = FmtBuffer::<512>::new();
130 let _ = write!(
131 &mut fmt_buffer,
132 "Attempted to copy data from a UserSlice ({} bytes) into an incorrectly sized slice ({} bytes)",
133 src_len,
134 dst_len
135 );
136
137 kernel_panic(
138 PanicCode::InternalKernelError,
139 fmt_buffer.as_str()
140 );
141 }
142}