strat9_kernel/syscall/
volume.rs1use super::error::SyscallError;
7use crate::{
8 capability::{CapId, CapPermissions, ResourceType},
9 hardware::storage::{
10 ahci,
11 virtio_block::{self, BlockDevice, SECTOR_SIZE},
12 },
13 memory::{UserSliceRead, UserSliceWrite},
14 process::current_task_clone,
15};
16
17const MAX_SECTORS_PER_CALL: u64 = 256;
18
19enum VolumeDeviceRef {
20 Virtio(&'static virtio_block::VirtioBlockDevice),
21 Ahci(&'static ahci::AhciController),
22}
23
24impl VolumeDeviceRef {
25 fn sector_count(&self) -> u64 {
26 match self {
27 VolumeDeviceRef::Virtio(dev) => BlockDevice::sector_count(*dev),
28 VolumeDeviceRef::Ahci(dev) => BlockDevice::sector_count(*dev),
29 }
30 }
31
32 fn read_sector(&self, sector: u64, buf: &mut [u8]) -> Result<(), SyscallError> {
33 match self {
34 VolumeDeviceRef::Virtio(dev) => {
35 BlockDevice::read_sector(*dev, sector, buf).map_err(SyscallError::from)
36 }
37 VolumeDeviceRef::Ahci(dev) => {
38 BlockDevice::read_sector(*dev, sector, buf).map_err(SyscallError::from)
39 }
40 }
41 }
42
43 fn write_sector(&self, sector: u64, buf: &[u8]) -> Result<(), SyscallError> {
44 match self {
45 VolumeDeviceRef::Virtio(dev) => {
46 BlockDevice::write_sector(*dev, sector, buf).map_err(SyscallError::from)
47 }
48 VolumeDeviceRef::Ahci(dev) => {
49 BlockDevice::write_sector(*dev, sector, buf).map_err(SyscallError::from)
50 }
51 }
52 }
53}
54
55fn resolve_volume_device(
56 handle: u64,
57 required: CapPermissions,
58) -> Result<VolumeDeviceRef, SyscallError> {
59 crate::silo::enforce_cap_for_current_task(handle)?;
60 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
61 let caps = unsafe { &*task.process.capabilities.get() };
62 let cap = caps
63 .get_with_permissions(CapId::from_raw(handle), required)
64 .ok_or(SyscallError::PermissionDenied)?;
65 if cap.resource_type != ResourceType::Volume {
66 return Err(SyscallError::BadHandle);
67 }
68
69 let ptr = cap.resource as *const ();
70 if let Some(dev) = virtio_block::get_device() {
72 if dev as *const _ as *const () == ptr {
73 return Ok(VolumeDeviceRef::Virtio(dev));
74 }
75 }
76 if let Some(dev) = ahci::get_device() {
77 if dev as *const _ as *const () == ptr {
78 return Ok(VolumeDeviceRef::Ahci(dev));
79 }
80 }
81 Err(SyscallError::BadHandle)
82}
83
84pub fn sys_volume_read(
86 handle: u64,
87 sector: u64,
88 buf_ptr: u64,
89 sector_count: u64,
90) -> Result<u64, SyscallError> {
91 if sector_count == 0 || sector_count > MAX_SECTORS_PER_CALL {
92 return Err(SyscallError::InvalidArgument);
93 }
94
95 let required = CapPermissions {
96 read: true,
97 write: false,
98 execute: false,
99 grant: false,
100 revoke: false,
101 };
102 let device = resolve_volume_device(handle, required)?;
103 let total_sectors = device.sector_count();
104 if sector >= total_sectors || sector.saturating_add(sector_count) > total_sectors {
105 return Err(SyscallError::InvalidArgument);
106 }
107
108 let mut kbuf = [0u8; SECTOR_SIZE];
109 let probe_trace = sector == 0;
110
111 for i in 0..sector_count {
112 let cur_sector = sector.checked_add(i).ok_or(SyscallError::InvalidArgument)?;
113 device.read_sector(cur_sector, &mut kbuf)?;
114 let offset = (i as usize)
115 .checked_mul(SECTOR_SIZE)
116 .ok_or(SyscallError::InvalidArgument)?;
117 let ptr = buf_ptr
118 .checked_add(offset as u64)
119 .ok_or(SyscallError::Fault)?;
120 let user = UserSliceWrite::new(ptr, SECTOR_SIZE)?;
121 user.copy_from(&kbuf);
122 if probe_trace {
123 crate::serial_println!(
124 "[volume-read] copied to user handle={} sector={} ptr={:#x}",
125 handle,
126 cur_sector,
127 ptr
128 );
129 }
130 }
131
132 Ok(sector_count)
133}
134
135pub fn sys_volume_write(
137 handle: u64,
138 sector: u64,
139 buf_ptr: u64,
140 sector_count: u64,
141) -> Result<u64, SyscallError> {
142 if sector_count == 0 {
143 return Ok(0);
144 }
145 if sector_count > MAX_SECTORS_PER_CALL {
146 return Err(SyscallError::InvalidArgument);
147 }
148
149 let required = CapPermissions {
150 read: false,
151 write: true,
152 execute: false,
153 grant: false,
154 revoke: false,
155 };
156 let device = resolve_volume_device(handle, required)?;
157 let total_sectors = device.sector_count();
158 if sector >= total_sectors || sector.saturating_add(sector_count) > total_sectors {
159 return Err(SyscallError::InvalidArgument);
160 }
161
162 let mut kbuf = [0u8; SECTOR_SIZE];
163 for i in 0..sector_count {
164 let cur_sector = sector.checked_add(i).ok_or(SyscallError::InvalidArgument)?;
165 let offset = (i as usize)
166 .checked_mul(SECTOR_SIZE)
167 .ok_or(SyscallError::InvalidArgument)?;
168 let ptr = buf_ptr
169 .checked_add(offset as u64)
170 .ok_or(SyscallError::Fault)?;
171 let user = UserSliceRead::new(ptr, SECTOR_SIZE)?;
172 let data = user.read_to_vec();
173 if data.len() != SECTOR_SIZE {
174 return Err(SyscallError::InvalidArgument);
175 }
176 kbuf.copy_from_slice(&data);
177 device.write_sector(cur_sector, &kbuf)?;
178 }
179
180 Ok(sector_count)
181}
182
183pub fn sys_volume_info(handle: u64) -> Result<u64, SyscallError> {
185 let required = CapPermissions {
186 read: true,
187 write: false,
188 execute: false,
189 grant: false,
190 revoke: false,
191 };
192 let device = resolve_volume_device(handle, required)?;
193 Ok(device.sector_count())
194}