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 user_fs_base: core::sync::atomic::AtomicU64::new(0),
166 fpu_state: crate::process::task::SyncUnsafeCell::new(fpu_state),
167 xcr0_mask: core::sync::atomic::AtomicU64::new(xcr0_mask),
168 rt_link: intrusive_collections::LinkedListLink::new(),
169 });
170
171 task.seed_interrupt_frame(crate::syscall::SyscallFrame {
172 r15: 0,
173 r14: 0,
174 r13: 0,
175 r12: 0,
176 rbp: 0,
177 rbx: 0,
178 r11: 0x202,
179 r10: 0,
180 r9: 0,
181 r8: 0,
182 rsi: 0,
183 rdi: 0,
184 rdx: 0,
185 rcx: USER_CODE_ADDR,
186 rax: 0,
187 iret_rip: USER_CODE_ADDR,
188 iret_cs: crate::arch::x86_64::gdt::user_code_selector().0 as u64,
189 iret_rflags: 0x202,
190 iret_rsp: USER_STACK_TOP,
191 iret_ss: crate::arch::x86_64::gdt::user_data_selector().0 as u64,
192 });
193
194 crate::process::add_task(task);
195 log::info!(
196 "Ring 3 test task created: code@{:#x}, stack@{:#x}",
197 USER_CODE_ADDR,
198 USER_STACK_TOP,
199 );
200}
201
202static mut USER_TASK_AS: Option<Arc<AddressSpace>> = None;
204
205extern "C" fn ring3_trampoline() -> ! {
212 use crate::arch::x86_64::gdt;
213
214 unsafe {
217 let user_as = &*(&raw const USER_TASK_AS);
218 if let Some(ref as_ref) = user_as {
219 as_ref.switch_to();
220
221 let phys = as_ref.translate(x86_64::VirtAddr::new(USER_CODE_ADDR));
223 crate::serial_println!(
224 "[ring3-tramp] CR3={:#x}, translate({:#x})={:?}",
225 as_ref.cr3().as_u64(),
226 USER_CODE_ADDR,
227 phys,
228 );
229
230 let (cr3_frame, _) = x86_64::registers::control::Cr3::read();
232 let cr3_phys = cr3_frame.start_address().as_u64();
233 let hhdm = crate::memory::hhdm_offset();
234 crate::serial_println!(
235 "[ring3-tramp] Active CR3={:#x} (expected {:#x})",
236 cr3_phys,
237 as_ref.cr3().as_u64(),
238 );
239
240 let l4_ptr = (cr3_phys + hhdm) as *const u64;
242 let l4_entry = *l4_ptr; crate::serial_println!(
244 "[ring3-tramp] PML4[0]={:#x} (present={})",
245 l4_entry,
246 l4_entry & 1,
247 );
248 } else {
249 crate::serial_println!("[ring3-tramp] ERROR: USER_TASK_AS is None!");
250 }
251 }
252
253 let user_cs = gdt::user_code_selector().0 as u64;
254 let user_ss = gdt::user_data_selector().0 as u64;
255 let user_rip = USER_CODE_ADDR;
256 let user_rsp = USER_STACK_TOP;
257 let user_rflags: u64 = 0x202; crate::serial_println!(
260 "[ring3-tramp] IRETQ: CS={:#x} RIP={:#x} SS={:#x} RSP={:#x} RFLAGS={:#x}",
261 user_cs,
262 user_rip,
263 user_ss,
264 user_rsp,
265 user_rflags,
266 );
267
268 unsafe {
270 core::arch::asm!(
271 "push {ss}", "push {rsp}", "push {rflags}", "push {cs}", "push {rip}", "swapgs",
277 "iretq",
278 ss = in(reg) user_ss,
279 rsp = in(reg) user_rsp,
280 rflags = in(reg) user_rflags,
281 cs = in(reg) user_cs,
282 rip = in(reg) user_rip,
283 options(noreturn),
284 );
285 }
286}
287
288fn write_user_code(dest: *mut u8) {
310 let code: &[u8] = &[
312 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'!',
334 ];
335
336 unsafe {
338 core::ptr::copy_nonoverlapping(code.as_ptr(), dest, code.len());
339 }
340}