Nothing to see here, move along
1use lancer_core::object_tag::ObjectTag;
2
3use super::object::{
4 CNodeData, EndpointData, FrameObjectData, IrqHandlerData, IrqSource, NotificationData,
5 ObjectData, PortRange, SchedContextData,
6};
7use super::pool::ObjectPool;
8use super::table::{CapRef, Rights};
9use crate::error::KernelError;
10use crate::types::{Generation, ObjectId, Priority};
11use x86_64::PhysAddr;
12
13const MAX_RETYPE_COUNT: u32 = 64;
14
15fn make_object_data(
16 tag: ObjectTag,
17 frame_phys: Option<PhysAddr>,
18 size_bits: u8,
19) -> Result<ObjectData, KernelError> {
20 match tag {
21 ObjectTag::Endpoint => Ok(ObjectData::Endpoint(EndpointData::new())),
22 ObjectTag::Notification => Ok(ObjectData::Notification(NotificationData::new())),
23 ObjectTag::Frame => {
24 let phys = frame_phys.ok_or(KernelError::InvalidParameter)?;
25 Ok(ObjectData::Frame(FrameObjectData::new_from_untyped(phys)))
26 }
27 ObjectTag::CNode => {
28 let phys = frame_phys.ok_or(KernelError::InvalidParameter)?;
29 let frame_count = lancer_core::cnode::frames_for_cnode(size_bits);
30 Ok(ObjectData::CNode(CNodeData {
31 slots_phys: phys,
32 size_bits,
33 frame_count,
34 }))
35 }
36 ObjectTag::SchedContext => Ok(ObjectData::SchedContext(SchedContextData::new(
37 0,
38 0,
39 Priority::IDLE,
40 ))),
41 ObjectTag::IrqHandler => Ok(ObjectData::IrqHandler(IrqHandlerData {
42 vector: crate::arch::x86_64::idt::IrqVector::new(32),
43 source: IrqSource::Ioapic {
44 gsi: crate::arch::ioapic::Gsi::new(0),
45 },
46 port_range: match PortRange::new(0, 1) {
47 Some(pr) => pr,
48 None => return Err(KernelError::InvalidParameter),
49 },
50 })),
51 ObjectTag::Untyped
52 | ObjectTag::Process
53 | ObjectTag::Framebuffer
54 | ObjectTag::PciDevice
55 | ObjectTag::MemoryRegion => Err(KernelError::InvalidType),
56
57 }
58}
59
60#[allow(clippy::too_many_arguments)]
61pub fn kernel_retype(
62 pool: &mut ObjectPool,
63 untyped_id: ObjectId,
64 untyped_gen: Generation,
65 obj_tag: ObjectTag,
66 size_bits: u8,
67 dest_cnode_id: ObjectId,
68 dest_cnode_gen: Generation,
69 dest_addr: u64,
70 dest_depth: u8,
71 count: u32,
72) -> Result<(), KernelError> {
73 match count > MAX_RETYPE_COUNT {
74 true => return Err(KernelError::InvalidParameter),
75 false => {}
76 }
77
78 let untyped_data = pool.get(untyped_id, untyped_gen)?;
79 let untyped = untyped_data.as_untyped()?;
80 let phys_base = untyped.phys_base;
81
82 let result = match obj_tag {
83 ObjectTag::Frame => {
84 untyped.state
85 .try_retype(ObjectTag::Frame, size_bits, count)
86 .map_err(retype_to_kernel_error)?
87 }
88 _ => {
89 make_object_data(obj_tag, None, size_bits)?;
90 let (obj_size, obj_align) = lancer_core::untyped::object_layout(obj_tag, size_bits)
91 .map_err(retype_to_kernel_error)?;
92 untyped.state
93 .try_allocate_raw(obj_size, obj_align, count)
94 .map_err(retype_to_kernel_error)?
95 }
96 };
97
98 let mut allocated: crate::static_vec::StaticVec<(ObjectId, Generation), { MAX_RETYPE_COUNT as usize }> =
99 crate::static_vec::StaticVec::new();
100
101 let rollback_result = (0..count).try_for_each(|i| {
102 let obj_phys = phys_base.as_u64() + result.start_offset() as u64
103 + (i as u64) * result.stride() as u64;
104
105 let phys_for_data = match obj_tag {
106 ObjectTag::Frame | ObjectTag::CNode => Some(PhysAddr::new(obj_phys)),
107 _ => None,
108 };
109
110 if obj_tag == ObjectTag::CNode {
111 let slot_count = 1usize << size_bits;
112 let hhdm = crate::mem::addr::hhdm_offset();
113 let base_ptr = (obj_phys + hhdm) as *mut u8;
114 let byte_count = slot_count * core::mem::size_of::<super::table::CapSlot>();
115 unsafe { core::ptr::write_bytes(base_ptr, 0, byte_count) };
116 }
117
118 let data = make_object_data(obj_tag, phys_for_data, size_bits)?;
119
120 let kern_result = pool
121 .allocate(data)
122 .map_err(|_| KernelError::PoolExhausted)?;
123 let (obj_id, obj_gen) = kern_result;
124
125 let cap = CapRef::new(obj_tag, obj_id, Rights::ALL, obj_gen);
126 let slot_addr = dest_addr + i as u64;
127 match super::cnode::resolve_and_insert(
128 pool,
129 dest_cnode_id,
130 dest_cnode_gen,
131 slot_addr,
132 dest_depth,
133 cap,
134 ) {
135 Ok(()) => {
136 let _ = allocated.push((obj_id, obj_gen));
137 Ok(())
138 }
139 Err(e) => {
140 let _ = pool.free(obj_id, obj_gen);
141 Err(e)
142 }
143 }
144 });
145
146 match rollback_result {
147 Ok(()) => {
148 let untyped_mut = pool.get_mut(untyped_id, untyped_gen)?;
149 let ut = untyped_mut.as_untyped_mut()?;
150 ut.state.commit_retype(&result);
151
152 match obj_tag {
153 ObjectTag::Frame => {
154 (0..count).for_each(|i| {
155 let frame_phys = phys_base.as_u64()
156 + result.start_offset() as u64
157 + (i as u64) * result.stride() as u64;
158 let frame_idx = (frame_phys / 4096) as usize;
159 crate::mem::phys::BitmapFrameAllocator::mark_used(frame_idx);
160 });
161 }
162 ObjectTag::CNode => {
163 let frame_count = lancer_core::cnode::frames_for_cnode(size_bits) as u32;
164 (0..count).for_each(|i| {
165 let cnode_phys = phys_base.as_u64()
166 + result.start_offset() as u64
167 + (i as u64) * result.stride() as u64;
168 (0..frame_count).for_each(|f| {
169 let frame_idx = ((cnode_phys + f as u64 * 4096) / 4096) as usize;
170 crate::mem::phys::BitmapFrameAllocator::mark_used(frame_idx);
171 });
172 });
173 }
174 _ => {}
175 }
176 Ok(())
177 }
178 Err(e) => {
179 allocated.as_slice().iter().enumerate().for_each(|(i, &(id, generation))| {
180 let slot_addr = dest_addr + i as u64;
181 let _ = super::cnode::resolve_and_clear(
182 pool, dest_cnode_id, dest_cnode_gen, slot_addr, dest_depth,
183 );
184 let _ = pool.free(id, generation);
185 });
186 Err(e)
187 }
188 }
189}
190
191fn retype_to_kernel_error(e: lancer_core::untyped::RetypeError) -> KernelError {
192 match e {
193 lancer_core::untyped::RetypeError::InsufficientSpace => KernelError::ResourceExhausted,
194 lancer_core::untyped::RetypeError::DeviceRejectsNonFrame => KernelError::InvalidType,
195 lancer_core::untyped::RetypeError::ZeroCount => KernelError::InvalidParameter,
196 lancer_core::untyped::RetypeError::Overflow => KernelError::InvalidParameter,
197 lancer_core::untyped::RetypeError::InvalidSizeBits => KernelError::InvalidParameter,
198 lancer_core::untyped::RetypeError::InvalidType => KernelError::InvalidType,
199 }
200}