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: SyncUnsafeCell::new(TaskState::Ready),
136 priority: TaskPriority::Normal,
137 context: SyncUnsafeCell::new(context),
138 kernel_stack,
139 user_stack: None,
140
141 name: "test-user-ring3",
142 process: alloc::sync::Arc::new(crate::process::process::Process::new(pid, user_as)),
143 pending_signals: super::signal::SignalSet::new(),
144
145 blocked_signals: super::signal::SignalSet::new(),
146 signal_stack: SyncUnsafeCell::new(None),
147 itimers: super::timer::ITimers::new(),
148 wake_pending: core::sync::atomic::AtomicBool::new(false),
149 wake_deadline_ns: core::sync::atomic::AtomicU64::new(0),
150 trampoline_entry: core::sync::atomic::AtomicU64::new(0),
151 trampoline_stack_top: core::sync::atomic::AtomicU64::new(0),
152 trampoline_arg0: core::sync::atomic::AtomicU64::new(0),
153 ticks: core::sync::atomic::AtomicU64::new(0),
154 sched_policy: crate::process::task::SyncUnsafeCell::new(Task::default_sched_policy(
155 TaskPriority::Normal,
156 )),
157 vruntime: core::sync::atomic::AtomicU64::new(0),
158 clear_child_tid: core::sync::atomic::AtomicU64::new(0),
159 user_fs_base: core::sync::atomic::AtomicU64::new(0),
160 fpu_state: crate::process::task::SyncUnsafeCell::new(fpu_state),
161 xcr0_mask: core::sync::atomic::AtomicU64::new(xcr0_mask),
162 });
163
164 crate::process::add_task(task);
165 log::info!(
166 "Ring 3 test task created: code@{:#x}, stack@{:#x}",
167 USER_CODE_ADDR,
168 USER_STACK_TOP,
169 );
170}
171
172static mut USER_TASK_AS: Option<Arc<AddressSpace>> = None;
174
175extern "C" fn ring3_trampoline() -> ! {
182 use crate::arch::x86_64::gdt;
183
184 unsafe {
187 let user_as = &*(&raw const USER_TASK_AS);
188 if let Some(ref as_ref) = user_as {
189 as_ref.switch_to();
190
191 let phys = as_ref.translate(x86_64::VirtAddr::new(USER_CODE_ADDR));
193 crate::serial_println!(
194 "[ring3-tramp] CR3={:#x}, translate({:#x})={:?}",
195 as_ref.cr3().as_u64(),
196 USER_CODE_ADDR,
197 phys,
198 );
199
200 let (cr3_frame, _) = x86_64::registers::control::Cr3::read();
202 let cr3_phys = cr3_frame.start_address().as_u64();
203 let hhdm = crate::memory::hhdm_offset();
204 crate::serial_println!(
205 "[ring3-tramp] Active CR3={:#x} (expected {:#x})",
206 cr3_phys,
207 as_ref.cr3().as_u64(),
208 );
209
210 let l4_ptr = (cr3_phys + hhdm) as *const u64;
212 let l4_entry = *l4_ptr; crate::serial_println!(
214 "[ring3-tramp] PML4[0]={:#x} (present={})",
215 l4_entry,
216 l4_entry & 1,
217 );
218 } else {
219 crate::serial_println!("[ring3-tramp] ERROR: USER_TASK_AS is None!");
220 }
221 }
222
223 let user_cs = gdt::user_code_selector().0 as u64;
224 let user_ss = gdt::user_data_selector().0 as u64;
225 let user_rip = USER_CODE_ADDR;
226 let user_rsp = USER_STACK_TOP;
227 let user_rflags: u64 = 0x202; crate::serial_println!(
230 "[ring3-tramp] IRETQ: CS={:#x} RIP={:#x} SS={:#x} RSP={:#x} RFLAGS={:#x}",
231 user_cs,
232 user_rip,
233 user_ss,
234 user_rsp,
235 user_rflags,
236 );
237
238 unsafe {
240 core::arch::asm!(
241 "push {ss}", "push {rsp}", "push {rflags}", "push {cs}", "push {rip}", "swapgs",
247 "iretq",
248 ss = in(reg) user_ss,
249 rsp = in(reg) user_rsp,
250 rflags = in(reg) user_rflags,
251 cs = in(reg) user_cs,
252 rip = in(reg) user_rip,
253 options(noreturn),
254 );
255 }
256}
257
258fn write_user_code(dest: *mut u8) {
280 let code: &[u8] = &[
282 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'!',
304 ];
305
306 unsafe {
308 core::ptr::copy_nonoverlapping(code.as_ptr(), dest, code.len());
309 }
310}