1use 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 fn read_sectors(&self, sector: u64, count: u16, buf: &mut [u8]) -> Result<(), SyscallError> {
55 match self {
56 VolumeDeviceRef::Virtio(dev) => {
57 BlockDevice::read_sectors(*dev, sector, count, buf).map_err(SyscallError::from)
58 }
59 VolumeDeviceRef::Ahci(dev) => {
60 BlockDevice::read_sectors(*dev, sector, count, buf).map_err(SyscallError::from)
61 }
62 }
63 }
64
65 fn write_sectors(&self, sector: u64, count: u16, buf: &[u8]) -> Result<(), SyscallError> {
66 match self {
67 VolumeDeviceRef::Virtio(dev) => {
68 BlockDevice::write_sectors(*dev, sector, count, buf).map_err(SyscallError::from)
69 }
70 VolumeDeviceRef::Ahci(dev) => {
71 BlockDevice::write_sectors(*dev, sector, count, buf).map_err(SyscallError::from)
72 }
73 }
74 }
75}
76
77fn resolve_volume_device(
78 handle: u64,
79 required: CapPermissions,
80) -> Result<VolumeDeviceRef, SyscallError> {
81 crate::silo::enforce_cap_for_current_task(handle)?;
82 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
83 let caps = unsafe { &*task.process.capabilities.get() };
84 let cap = caps
85 .get_with_permissions(CapId::from_raw(handle), required)
86 .ok_or(SyscallError::PermissionDenied)?;
87 if cap.resource_type != ResourceType::Volume {
88 return Err(SyscallError::BadHandle);
89 }
90
91 let ptr = cap.resource as *const ();
92 if let Some(dev) = virtio_block::get_device() {
94 if dev as *const _ as *const () == ptr {
95 return Ok(VolumeDeviceRef::Virtio(dev));
96 }
97 }
98 if let Some(dev) = ahci::get_device() {
99 if dev as *const _ as *const () == ptr {
100 return Ok(VolumeDeviceRef::Ahci(dev));
101 }
102 }
103 Err(SyscallError::BadHandle)
104}
105
106pub fn sys_volume_read(
108 handle: u64,
109 sector: u64,
110 buf_ptr: u64,
111 sector_count: u64,
112) -> Result<u64, SyscallError> {
113 if sector_count == 0 || sector_count > MAX_SECTORS_PER_CALL {
114 return Err(SyscallError::InvalidArgument);
115 }
116
117 let required = CapPermissions {
118 read: true,
119 write: false,
120 execute: false,
121 grant: false,
122 revoke: false,
123 };
124 let device = resolve_volume_device(handle, required)?;
125 let total_sectors = device.sector_count();
126 if sector >= total_sectors || sector.saturating_add(sector_count) > total_sectors {
127 return Err(SyscallError::InvalidArgument);
128 }
129
130 let count = sector_count as u16;
131 let nbytes = (count as usize) * SECTOR_SIZE;
132
133 let mut kbuf = alloc::vec![0u8; nbytes];
137 let buf_slice = &mut kbuf[..nbytes];
138 device.read_sectors(sector, count, buf_slice)?;
139
140 let user = UserSliceWrite::new(buf_ptr, nbytes)?;
141 user.copy_from(buf_slice);
142
143 if sector == 0 {
144 crate::serial_println!(
145 "[volume-read] bulk handle={} sector={} count={} ptr={:#x}",
146 handle,
147 sector,
148 sector_count,
149 buf_ptr
150 );
151 }
152
153 Ok(sector_count)
154}
155
156pub fn sys_volume_write(
158 handle: u64,
159 sector: u64,
160 buf_ptr: u64,
161 sector_count: u64,
162) -> Result<u64, SyscallError> {
163 if sector_count == 0 {
164 return Ok(0);
165 }
166 if sector_count > MAX_SECTORS_PER_CALL {
167 return Err(SyscallError::InvalidArgument);
168 }
169
170 let required = CapPermissions {
171 read: false,
172 write: true,
173 execute: false,
174 grant: false,
175 revoke: false,
176 };
177 let device = resolve_volume_device(handle, required)?;
178 let total_sectors = device.sector_count();
179 if sector >= total_sectors || sector.saturating_add(sector_count) > total_sectors {
180 return Err(SyscallError::InvalidArgument);
181 }
182
183 let count = sector_count as u16;
184 let nbytes = (count as usize) * SECTOR_SIZE;
185
186 let user = UserSliceRead::new(buf_ptr, nbytes)?;
190 let kbuf = user.read_to_vec();
191 if kbuf.len() != nbytes {
192 return Err(SyscallError::InvalidArgument);
193 }
194 device.write_sectors(sector, count, &kbuf)?;
195
196 Ok(sector_count)
197}
198
199pub fn sys_volume_info(handle: u64) -> Result<u64, SyscallError> {
201 let required = CapPermissions {
202 read: true,
203 write: false,
204 execute: false,
205 grant: false,
206 revoke: false,
207 };
208 let device = resolve_volume_device(handle, required)?;
209 Ok(device.sector_count())
210}