veridian_kernel/desktop/
kde_session.rs1#![allow(dead_code)]
12
13#[cfg(feature = "alloc")]
14extern crate alloc;
15
16const MIN_SESSION_LIFETIME_ITERS: u64 = 500;
24
25const KDE_INIT_SCRIPT: &str = "/usr/share/veridian/veridian-kde-init.sh";
27
28const KWIN_WAYLAND: &str = "/usr/bin/kwin_wayland";
30
31const DBUS_DAEMON: &str = "/usr/bin/dbus-daemon";
33
34const KDE_ENV: &[&str] = &[
36 "HOME=/root",
37 "USER=root",
38 "SHELL=/bin/sh",
39 "PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
40 "XDG_RUNTIME_DIR=/run/user/0",
41 "XDG_SESSION_TYPE=wayland",
42 "XDG_CURRENT_DESKTOP=KDE",
43 "WAYLAND_DISPLAY=wayland-0",
44 "DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
45 "QT_QPA_PLATFORM=veridian",
46 "LANG=en_US.UTF-8",
47];
48
49#[cfg(all(feature = "alloc", target_arch = "x86_64"))]
63pub fn start_kde_session() {
64 println!("[KDE] Starting KDE Plasma 6 session...");
65
66 match crate::desktop::init() {
70 Ok(()) => println!("[KDE] Desktop subsystem initialized"),
71 Err(crate::error::KernelError::InvalidState { .. }) => {
72 println!("[KDE] Desktop already initialized, switching to KDE session");
73 }
74 Err(e) => {
75 println!("[KDE] Desktop subsystem init failed: {:?}", e);
76 println!("[KDE] Falling back to built-in desktop...");
77 crate::desktop::renderer::start_desktop();
78 return;
79 }
80 }
81
82 crate::graphics::fbcon::disable_output();
84 println!("[KDE] Framebuffer console disabled (KWin will drive display)");
85
86 let pid = match launch_kde_init() {
88 Ok(pid) => {
89 println!("[KDE] KDE process launched (PID {})", pid.0);
90 pid
91 }
92 Err(e) => {
93 println!("[KDE] Failed to launch KDE session: {:?}", e);
94 println!("[KDE] Falling back to built-in desktop...");
95 crate::graphics::fbcon::enable_output();
96 crate::graphics::fbcon::mark_all_dirty_and_flush();
97 crate::desktop::renderer::start_desktop();
98 return;
99 }
100 };
101
102 let start_iter = get_iteration_counter();
104 run_kde_process(pid);
105 let end_iter = get_iteration_counter();
106
107 crate::graphics::fbcon::enable_output();
109 crate::graphics::fbcon::mark_all_dirty_and_flush();
110 println!("[KDE] Session ended, text console restored");
111
112 let elapsed = end_iter.saturating_sub(start_iter);
114 if elapsed < MIN_SESSION_LIFETIME_ITERS {
115 println!(
116 "[KDE] Session exited unexpectedly (within ~{}s of launch)",
117 elapsed / 100
118 );
119 println!("[KDE] Falling back to built-in desktop...");
120 crate::desktop::renderer::start_desktop();
121 }
122}
123
124#[cfg(feature = "alloc")]
134fn launch_kde_init() -> Result<crate::process::ProcessId, crate::error::KernelError> {
135 let shell_argv: &[&str] = &["sh", KDE_INIT_SCRIPT, "--from-kernel"];
137 if let Ok(pid) = crate::userspace::load_user_program("/bin/sh", shell_argv, KDE_ENV) {
138 println!("[KDE] Launched via init script (/bin/sh)");
139 return Ok(pid);
140 }
141
142 let kwin_argv: &[&str] = &["kwin_wayland", "--no-lockscreen"];
144 if let Ok(pid) = crate::userspace::load_user_program(KWIN_WAYLAND, kwin_argv, KDE_ENV) {
145 println!("[KDE] Launched kwin_wayland directly");
146 return Ok(pid);
147 }
148 println!("[KDE] kwin_wayland not loadable, trying dbus-daemon...");
149
150 let dbus_argv: &[&str] = &["dbus-daemon", "--session", "--nofork"];
152 if let Ok(pid) = crate::userspace::load_user_program(DBUS_DAEMON, dbus_argv, KDE_ENV) {
153 println!("[KDE] Launched dbus-daemon (smoke test)");
154 return Ok(pid);
155 }
156
157 Err(crate::error::KernelError::NotFound {
158 resource: "KDE binaries (kwin_wayland, dbus-daemon)",
159 id: 0,
160 })
161}
162
163#[cfg(all(feature = "alloc", target_arch = "x86_64"))]
169fn run_kde_process(pid: crate::process::ProcessId) {
170 use crate::process::get_process;
171
172 let saved_pt_root = if let Some(proc) = get_process(pid) {
174 proc.memory_space.lock().get_page_table()
175 } else {
176 0
177 };
178
179 let tid = if let Some(proc) = get_process(pid) {
181 let threads = proc.threads.lock();
182 threads.values().next().map(|t| t.tid)
183 } else {
184 None
185 };
186
187 if let Some(tid) = tid {
189 crate::process::set_boot_current(pid, tid);
190 crate::bootstrap::run_user_process(pid);
191 crate::process::clear_boot_current();
192 } else {
193 crate::bootstrap::run_user_process(pid);
194 }
195
196 let current_pt_root = if let Some(proc) = get_process(pid) {
199 proc.memory_space.lock().get_page_table()
200 } else {
201 0
202 };
203
204 if current_pt_root != 0 && current_pt_root != saved_pt_root {
205 crate::mm::vas::free_user_page_table_frames(current_pt_root);
206 }
207 if saved_pt_root != 0 {
208 crate::mm::vas::free_user_page_table_frames(saved_pt_root);
209 }
210
211 if let Some(proc) = get_process(pid) {
213 proc.memory_space.lock().set_page_table(0);
214 }
215
216 if let Some(proc) = get_process(pid) {
218 let state = proc.get_state();
219 if state == crate::process::ProcessState::Zombie
220 || state == crate::process::ProcessState::Dead
221 {
222 crate::process::table::remove_process(pid);
223 }
224 }
225}
226
227fn get_iteration_counter() -> u64 {
232 #[cfg(target_arch = "x86_64")]
233 {
234 unsafe { core::arch::x86_64::_rdtsc() / 1_000_000 }
237 }
238 #[cfg(not(target_arch = "x86_64"))]
239 {
240 0
241 }
242}
243
244#[cfg(not(all(feature = "alloc", target_arch = "x86_64")))]
246pub fn start_kde_session() {
247 crate::println!("[KDE] KDE session not supported on this architecture");
248 crate::println!("[KDE] Falling back to built-in desktop...");
249 crate::desktop::renderer::start_desktop();
250}
251
252#[cfg(test)]
257mod tests {
258 use super::*;
259
260 #[test]
261 fn test_kde_env_has_required_vars() {
262 let has_display = KDE_ENV.iter().any(|e| e.starts_with("WAYLAND_DISPLAY="));
263 let has_desktop = KDE_ENV
264 .iter()
265 .any(|e| e.starts_with("XDG_CURRENT_DESKTOP="));
266 let has_qpa = KDE_ENV.iter().any(|e| e.starts_with("QT_QPA_PLATFORM="));
267 assert!(has_display, "WAYLAND_DISPLAY must be set");
268 assert!(has_desktop, "XDG_CURRENT_DESKTOP must be set");
269 assert!(has_qpa, "QT_QPA_PLATFORM must be set");
270 }
271
272 #[test]
273 fn test_min_session_lifetime() {
274 assert!(MIN_SESSION_LIFETIME_ITERS >= 100);
276 }
277
278 #[test]
279 fn test_kde_init_script_path() {
280 assert!(KDE_INIT_SCRIPT.starts_with("/usr/share/"));
281 assert!(KDE_INIT_SCRIPT.ends_with(".sh"));
282 }
283
284 #[test]
285 fn test_kde_binary_paths() {
286 assert!(KWIN_WAYLAND.starts_with("/usr/bin/"));
287 assert!(DBUS_DAEMON.starts_with("/usr/bin/"));
288 }
289}