1use alloc::sync::Arc;
10use x86_64::VirtAddr;
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
143 name: "test-user-ring3",
144 process: alloc::sync::Arc::new(crate::process::process::Process::new(pid, user_as)),
145 pending_signals: super::signal::SignalSet::new(),
146
147 blocked_signals: super::signal::SignalSet::new(),
148 irq_signal_delivery_blocked: core::sync::atomic::AtomicBool::new(false),
149 signal_stack: SyncUnsafeCell::new(None),
150 itimers: super::timer::ITimers::new(),
151 wake_pending: core::sync::atomic::AtomicBool::new(false),
152 wake_deadline_ns: core::sync::atomic::AtomicU64::new(0),
153 trampoline_entry: core::sync::atomic::AtomicU64::new(0),
154 trampoline_stack_top: core::sync::atomic::AtomicU64::new(0),
155 trampoline_arg0: core::sync::atomic::AtomicU64::new(0),
156 ticks: core::sync::atomic::AtomicU64::new(0),
157 sched_policy: crate::process::task::SyncUnsafeCell::new(Task::default_sched_policy(
158 TaskPriority::Normal,
159 )),
160 home_cpu: core::sync::atomic::AtomicUsize::new(usize::MAX),
161 vruntime: core::sync::atomic::AtomicU64::new(0),
162 fair_rq_generation: core::sync::atomic::AtomicU64::new(0),
163 fair_on_rq: core::sync::atomic::AtomicBool::new(false),
164 clear_child_tid: core::sync::atomic::AtomicU64::new(0),
165 robust_list_head: core::sync::atomic::AtomicU64::new(0),
166 robust_list_len: core::sync::atomic::AtomicUsize::new(0),
167 user_fs_base: core::sync::atomic::AtomicU64::new(0),
168 fpu_state: crate::process::task::SyncUnsafeCell::new(fpu_state),
169 xcr0_mask: core::sync::atomic::AtomicU64::new(xcr0_mask),
170 rt_link: intrusive_collections::LinkedListLink::new(),
171 });
172
173 task.seed_interrupt_frame(crate::syscall::SyscallFrame {
174 r15: 0,
175 r14: 0,
176 r13: 0,
177 r12: 0,
178 rbp: 0,
179 rbx: 0,
180 r11: 0x202,
181 r10: 0,
182 r9: 0,
183 r8: 0,
184 rsi: 0,
185 rdi: 0,
186 rdx: 0,
187 rcx: USER_CODE_ADDR,
188 rax: 0,
189 iret_rip: USER_CODE_ADDR,
190 iret_cs: crate::arch::x86_64::gdt::user_code_selector().0 as u64,
191 iret_rflags: 0x202,
192 iret_rsp: USER_STACK_TOP,
193 iret_ss: crate::arch::x86_64::gdt::user_data_selector().0 as u64,
194 });
195
196 crate::process::add_task(task);
197 log::info!(
198 "Ring 3 test task created: code@{:#x}, stack@{:#x}",
199 USER_CODE_ADDR,
200 USER_STACK_TOP,
201 );
202}
203
204static mut USER_TASK_AS: Option<Arc<AddressSpace>> = None;
206
207extern "C" fn ring3_trampoline() -> ! {
214 use crate::arch::x86_64::gdt;
215
216 unsafe {
219 let user_as = &*(&raw const USER_TASK_AS);
220 if let Some(ref as_ref) = user_as {
221 as_ref.switch_to();
222
223 let phys = as_ref.translate(x86_64::VirtAddr::new(USER_CODE_ADDR));
225 crate::serial_println!(
226 "[ring3-tramp] CR3={:#x}, translate({:#x})={:?}",
227 as_ref.cr3().as_u64(),
228 USER_CODE_ADDR,
229 phys,
230 );
231
232 let (cr3_frame, _) = x86_64::registers::control::Cr3::read();
234 let cr3_phys = cr3_frame.start_address().as_u64();
235 let hhdm = crate::memory::hhdm_offset();
236 crate::serial_println!(
237 "[ring3-tramp] Active CR3={:#x} (expected {:#x})",
238 cr3_phys,
239 as_ref.cr3().as_u64(),
240 );
241
242 let l4_ptr = (cr3_phys + hhdm) as *const u64;
244 let l4_entry = *l4_ptr; crate::serial_println!(
246 "[ring3-tramp] PML4[0]={:#x} (present={})",
247 l4_entry,
248 l4_entry & 1,
249 );
250 } else {
251 crate::serial_println!("[ring3-tramp] ERROR: USER_TASK_AS is None!");
252 }
253 }
254
255 let user_cs = gdt::user_code_selector().0 as u64;
256 let user_ss = gdt::user_data_selector().0 as u64;
257 let user_rip = USER_CODE_ADDR;
258 let user_rsp = USER_STACK_TOP;
259 let user_rflags: u64 = 0x202; crate::serial_println!(
262 "[ring3-tramp] IRETQ: CS={:#x} RIP={:#x} SS={:#x} RSP={:#x} RFLAGS={:#x}",
263 user_cs,
264 user_rip,
265 user_ss,
266 user_rsp,
267 user_rflags,
268 );
269
270 unsafe {
272 core::arch::asm!(
273 "push {ss}", "push {rsp}", "push {rflags}", "push {cs}", "push {rip}", "swapgs",
279 "iretq",
280 ss = in(reg) user_ss,
281 rsp = in(reg) user_rsp,
282 rflags = in(reg) user_rflags,
283 cs = in(reg) user_cs,
284 rip = in(reg) user_rip,
285 options(noreturn),
286 );
287 }
288}
289
290fn write_user_code(dest: *mut u8) {
312 let code: &[u8] = &[
314 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'!',
336 ];
337
338 unsafe {
340 core::ptr::copy_nonoverlapping(code.as_ptr(), dest, code.len());
341 }
342}