1use crate::arch::xshim::VirtAddr;
10use alloc::sync::Arc;
11
12use crate::{
13 memory::address_space::{AddressSpace, VmaFlags, VmaType},
14 process::{
15 task::{CpuContext, KernelStack, SyncUnsafeCell, Task, TaskPriority},
16 TaskState,
17 },
18};
19
20const USER_CODE_ADDR: u64 = 0x40_0000;
22
23const USER_STACK_ADDR: u64 = 0x80_0000;
25
26const USER_STACK_TOP: u64 = USER_STACK_ADDR + 0x1000;
28
29pub fn create_user_test_task() {
38 log::info!("Creating Ring 3 test task...");
39
40 let user_as = match AddressSpace::new_user() {
42 Ok(a) => Arc::new(a),
43 Err(e) => {
44 log::error!("Failed to create user address space: {}", e);
45 return;
46 }
47 };
48
49 let code_flags = VmaFlags {
51 readable: true,
52 writable: false,
53 executable: true,
54 user_accessible: true,
55 };
56 if let Err(e) = user_as.map_region(
57 USER_CODE_ADDR,
58 1,
59 code_flags,
60 VmaType::Code,
61 crate::memory::address_space::VmaPageSize::Small,
62 ) {
63 log::error!("Failed to map user code page: {}", e);
64 return;
65 }
66
67 let stack_flags = VmaFlags {
69 readable: true,
70 writable: true,
71 executable: false,
72 user_accessible: true,
73 };
74 if let Err(e) = user_as.map_region(
75 USER_STACK_ADDR,
76 1,
77 stack_flags,
78 VmaType::Stack,
79 crate::memory::address_space::VmaPageSize::Small,
80 ) {
81 log::error!("Failed to map user stack page: {}", e);
82 return;
83 }
84
85 let code_phys = user_as.translate(VirtAddr::new(USER_CODE_ADDR));
89 let code_phys = match code_phys {
90 Some(p) => p,
91 None => {
92 log::error!("Failed to translate user code page");
93 return;
94 }
95 };
96 let code_virt = crate::memory::phys_to_virt(code_phys.as_u64());
97
98 write_user_code(code_virt as *mut u8);
100
101 unsafe {
106 let ptr = &raw mut USER_TASK_AS;
107 *ptr = Some(user_as.clone());
108 }
109
110 let kernel_stack = match KernelStack::allocate(Task::DEFAULT_STACK_SIZE) {
112 Ok(s) => s,
113 Err(e) => {
114 log::error!("Failed to allocate kernel stack for user task: {}", e);
115 return;
116 }
117 };
118
119 let context = CpuContext::new(ring3_trampoline as *const () as u64, &kernel_stack);
120 let (pid, tid, tgid) = Task::allocate_process_ids();
121 let fpu_state = crate::process::task::ExtendedState::new();
122 let xcr0_mask = fpu_state.xcr0_mask;
123
124 let task = Arc::new(Task {
125 id: crate::process::TaskId::new(),
126 pid,
127 tid,
128 tgid,
129 pgid: core::sync::atomic::AtomicU32::new(pid),
130 sid: core::sync::atomic::AtomicU32::new(pid),
131 uid: core::sync::atomic::AtomicU32::new(0),
132 euid: core::sync::atomic::AtomicU32::new(0),
133 gid: core::sync::atomic::AtomicU32::new(0),
134 egid: core::sync::atomic::AtomicU32::new(0),
135 state: core::sync::atomic::AtomicU8::new(TaskState::Ready as u8),
136 priority: TaskPriority::Normal,
137 context: SyncUnsafeCell::new(context),
138 resume_kind: SyncUnsafeCell::new(crate::process::task::ResumeKind::RetFrame),
139 interrupt_rsp: core::sync::atomic::AtomicU64::new(0),
140 kernel_stack,
141 user_stack: None,
142 stack_canary: core::sync::atomic::AtomicU64::new(0),
143 stack_canary_addr: core::sync::atomic::AtomicU64::new(0),
144 kernel_stack_user: SyncUnsafeCell::new(None),
145
146 name: "test-user-ring3",
147 process: alloc::sync::Arc::new(crate::process::process::Process::new(pid, user_as)),
148 pending_signals: super::signal::SignalSet::new(),
149
150 blocked_signals: super::signal::SignalSet::new(),
151 irq_signal_delivery_blocked: core::sync::atomic::AtomicBool::new(false),
152 signal_stack: SyncUnsafeCell::new(None),
153 itimers: super::timer::ITimers::new(),
154 wake_pending: core::sync::atomic::AtomicBool::new(false),
155 wake_deadline_ns: core::sync::atomic::AtomicU64::new(0),
156 trampoline_entry: core::sync::atomic::AtomicU64::new(0),
157 trampoline_stack_top: core::sync::atomic::AtomicU64::new(0),
158 trampoline_arg0: core::sync::atomic::AtomicU64::new(0),
159 ticks: core::sync::atomic::AtomicU64::new(0),
160 sched_policy: crate::process::task::SyncUnsafeCell::new(Task::default_sched_policy(
161 TaskPriority::Normal,
162 )),
163 home_cpu: core::sync::atomic::AtomicUsize::new(usize::MAX),
164 last_cpu: core::sync::atomic::AtomicUsize::new(usize::MAX),
165 affinity_mask: core::sync::atomic::AtomicU64::new(0),
166 vruntime: core::sync::atomic::AtomicU64::new(0),
167 fair_rq_generation: core::sync::atomic::AtomicU64::new(0),
168 fair_on_rq: core::sync::atomic::AtomicBool::new(false),
169 clear_child_tid: core::sync::atomic::AtomicU64::new(0),
170 robust_list_head: core::sync::atomic::AtomicU64::new(0),
171 robust_list_len: core::sync::atomic::AtomicUsize::new(0),
172 user_fs_base: core::sync::atomic::AtomicU64::new(0),
173 fpu_state: crate::process::task::SyncUnsafeCell::new(fpu_state),
174 xcr0_mask: core::sync::atomic::AtomicU64::new(xcr0_mask),
175 rt_link: intrusive_collections::LinkedListLink::new(),
176 rt_budget_remaining: core::sync::atomic::AtomicU64::new(0),
177 rt_budget_period_start: core::sync::atomic::AtomicU64::new(0),
178 rt_degraded: core::sync::atomic::AtomicBool::new(false),
179 fair_wait_ticks: core::sync::atomic::AtomicU64::new(0),
180 });
181
182 task.seed_interrupt_frame(crate::syscall::SyscallFrame {
183 r15: 0,
184 r14: 0,
185 r13: 0,
186 r12: 0,
187 rbp: 0,
188 rbx: 0,
189 r11: 0x202,
190 r10: 0,
191 r9: 0,
192 r8: 0,
193 rsi: 0,
194 rdi: 0,
195 rdx: 0,
196 rcx: USER_CODE_ADDR,
197 rax: 0,
198 iret_rip: USER_CODE_ADDR,
199 iret_cs: crate::arch::gdt::user_code_selector().0 as u64,
200 iret_rflags: 0x202,
201 iret_rsp: USER_STACK_TOP,
202 iret_ss: crate::arch::gdt::user_data_selector().0 as u64,
203 });
204
205 crate::process::add_task(task);
206 log::info!(
207 "Ring 3 test task created: code@{:#x}, stack@{:#x}",
208 USER_CODE_ADDR,
209 USER_STACK_TOP,
210 );
211}
212
213static mut USER_TASK_AS: Option<Arc<AddressSpace>> = None;
215
216extern "C" fn ring3_trampoline() -> ! {
223 use crate::arch::gdt;
224
225 unsafe {
228 let user_as = &*(&raw const USER_TASK_AS);
229 if let Some(ref as_ref) = user_as {
230 as_ref.switch_to();
231
232 let phys = as_ref.translate(crate::arch::xshim::VirtAddr::new(USER_CODE_ADDR));
234 crate::serial_println!(
235 "[ring3-tramp] CR3={:#x}, translate({:#x})={:?}",
236 as_ref.cr3().as_u64(),
237 USER_CODE_ADDR,
238 phys,
239 );
240
241 let (cr3_frame, _) = crate::x86_crate_shim::registers::control::Cr3::read();
243 let cr3_phys = cr3_frame.start_address().as_u64();
244 let hhdm = crate::memory::hhdm_offset();
245 crate::serial_println!(
246 "[ring3-tramp] Active CR3={:#x} (expected {:#x})",
247 cr3_phys,
248 as_ref.cr3().as_u64(),
249 );
250
251 let l4_ptr = (cr3_phys + hhdm) as *const u64;
253 let l4_entry = *l4_ptr; crate::serial_println!(
255 "[ring3-tramp] PML4[0]={:#x} (present={})",
256 l4_entry,
257 l4_entry & 1,
258 );
259 } else {
260 crate::serial_println!("[ring3-tramp] ERROR: USER_TASK_AS is None!");
261 }
262 }
263
264 let user_cs = gdt::user_code_selector().0 as u64;
265 let user_ss = gdt::user_data_selector().0 as u64;
266 let user_rip = USER_CODE_ADDR;
267 let user_rsp = USER_STACK_TOP;
268 let user_rflags: u64 = 0x202; crate::serial_println!(
271 "[ring3-tramp] IRETQ: CS={:#x} RIP={:#x} SS={:#x} RSP={:#x} RFLAGS={:#x}",
272 user_cs,
273 user_rip,
274 user_ss,
275 user_rsp,
276 user_rflags,
277 );
278
279 unsafe {
281 core::arch::asm!(
282 "push {ss}", "push {rsp}", "push {rflags}", "push {cs}", "push {rip}", "swapgs",
288 "iretq",
289 ss = in(reg) user_ss,
290 rsp = in(reg) user_rsp,
291 rflags = in(reg) user_rflags,
292 cs = in(reg) user_cs,
293 rip = in(reg) user_rip,
294 options(noreturn),
295 );
296 }
297}
298
299fn write_user_code(dest: *mut u8) {
321 let code: &[u8] = &[
323 0x48, 0xC7, 0xC0, 0x58, 0x02, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0x18, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC6, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x05, 0x48, 0xC7, 0xC0, 0x2C, 0x01, 0x00, 0x00, 0x48, 0x31, 0xFF, 0x0F, 0x05, 0xF4, 0xEB, 0xFD, b'H', b'e', b'l', b'l', b'o', b' ', b'R', b'i', b'n', b'g', b' ', b'3', b'!',
345 ];
346
347 unsafe {
349 core::ptr::copy_nonoverlapping(code.as_ptr(), dest, code.len());
350 }
351}