1#![cfg_attr(not(test), no_std)]
2#![cfg_attr(not(test), no_main)]
3#![allow(dead_code)]
4#![allow(static_mut_refs)]
5#![allow(clippy::needless_range_loop)]
11#![allow(clippy::too_many_arguments)]
12#![allow(clippy::type_complexity)]
13#![deny(clippy::string_slice)]
18
19extern crate alloc;
20
21use core::arch::global_asm;
22use core::panic::PanicInfo;
23
24#[cfg(not(test))]
26global_asm!(include_str!("kernel/boot.S"));
27
28#[macro_use]
29pub mod kernel;
30pub mod apps;
31pub mod os_lib;
32
33use kernel::draw::Screen;
34use kernel::mailbox::{FrameBufferRequest, Mailbox};
35use kernel::uart::Uart;
36
37pub const AUTO_TEST_BROWSER: bool = true; pub struct SystemState {
44 pub tick: u64,
45}
46
47pub struct KeyRepeatParams {
48 pub first_delay_ms: u32,
49 pub first_interval_ms: u32,
50 pub second_repeat_count: u32,
51 pub second_delay_ms: u32,
52 pub second_interval_ms: u32,
53}
54
55pub static mut REPEAT_PARAMS: KeyRepeatParams = KeyRepeatParams {
56 first_delay_ms: 200,
57 first_interval_ms: 15,
58 second_repeat_count: 25,
59 second_delay_ms: 10000,
60 second_interval_ms: 30,
61};
62
63struct KeyRepeatState {
64 active_keycode: u8,
65 press_start_ms: u64,
66 last_repeat_ms: u64,
67 stage: u8, }
69
70static mut REPEAT_STATE: KeyRepeatState = KeyRepeatState {
71 active_keycode: 0,
72 press_start_ms: 0,
73 last_repeat_ms: 0,
74 stage: 0,
75};
76
77pub static mut CURRENT_SCREEN: Option<Screen> = None;
79
80extern "C" {
81 static exception_vector_table: u8;
82 static __bss_end: u8;
83 static __cpu_stacks_end: u8;
84 static mut __cpu_stacks_start: u64;
85
86 static mut spin_cpu1: u64;
87 static mut spin_cpu2: u64;
88 static mut spin_cpu3: u64;
89
90 fn secondary_entry();
91}
92
93const STACK_CANARY_MAGIC: u64 = 0xDEAD_BEEF_CAFE_BABE;
103
104unsafe fn write_stack_canary() {
107 let ptr = core::ptr::addr_of_mut!(__cpu_stacks_start);
108 core::ptr::write_volatile(ptr, STACK_CANARY_MAGIC);
109}
110
111unsafe fn check_stack_canary() -> bool {
116 let ptr = core::ptr::addr_of!(__cpu_stacks_start);
117 core::ptr::read_volatile(ptr) == STACK_CANARY_MAGIC
118}
119
120fn report_stack_canary_violation(context: &str) {
128 println!("==================================================");
129 println!("!!! STACK OVERFLOW DETECTED (software canary) !!!");
130 println!("==================================================");
131 println!(" Context: {}", context);
132 println!(
133 " Core0 stack base (__cpu_stacks_start) canary value was overwritten."
134 );
135 println!(
136 " Expected: 0x{:016x}",
137 STACK_CANARY_MAGIC
138 );
139 println!(
140 " This means some function used more than 64KB of stack and silently"
141 );
142 println!(
143 " corrupted adjacent .bss memory (no MMU guard page here yet)."
144 );
145 println!("==================================================");
146}
147
148#[no_mangle]
149pub extern "C" fn kmain() -> ! {
150 Uart::init();
152 unsafe {
155 write_stack_canary();
156 }
157 println!("==================================================");
158 println!(" AtmOS v3 (ARM64 / OS Base) starting...");
159 println!(
160 " Version: {} (Git: {})",
161 crate::kernel::fs::BUILD_VERSION,
162 crate::kernel::fs::BUILD_GIT_HASH
163 );
164 println!(" Build Time: {}", crate::kernel::fs::BUILD_TIME);
165 println!(" Author: SUGIMURA Hiroshi (Sugimura Laboratory)");
166 println!("==================================================");
167 crate::warn!(
168 "[SYS] Build v{} git:{} {}",
169 crate::kernel::fs::BUILD_VERSION,
170 crate::kernel::fs::BUILD_GIT_HASH,
171 crate::kernel::fs::BUILD_TIME
172 );
173
174 crate::info!("[GPU] Attempting FrameBuffer allocation with fallback resolutions...");
178 let resolutions: [(u32, u32); 5] = [
179 (1024, 600), (1280, 720),
181 (1920, 1080),
182 (1024, 768),
183 (640, 480),
184 ];
185
186 let mut fb_info = None;
187 for &(w, h) in resolutions.iter() {
188 crate::debug!("[GPU] Trying {}x{}...", w, h);
189 let mut mbox_req = FrameBufferRequest::new(w, h);
190 let buf_ptr = &mut mbox_req as *mut FrameBufferRequest as *mut u32;
191 let buf_slice = unsafe { core::slice::from_raw_parts_mut(buf_ptr, 32) };
192
193 unsafe {
196 let addr = buf_slice.as_ptr() as usize;
197 let size = buf_slice.len() * 4;
198 let cache_line = 64usize;
199 let start = addr & !(cache_line - 1);
200 let end = addr + size;
201 let mut cur = start;
202 while cur < end {
203 core::arch::asm!("dc civac, {}", in(reg) cur, options(nostack));
204 cur += cache_line;
205 }
206 core::arch::asm!("dsb sy", options(nostack));
207 }
208
209 if Mailbox::call(buf_slice, kernel::mailbox::MBOX_CH_PROP).is_ok() {
210 if let Some(info) = mbox_req.get_info() {
211 let fb_addr = info.pointer as usize;
212 let uncached = fb_addr >= kernel::mmu::DEVICE_REGION_START;
214 crate::info!(
215 "[GPU] FrameBuffer OK: {}x{} pitch={} vptr={:?} vh={} size={}",
216 info.width,
217 info.height,
218 info.pitch,
219 info.pointer,
220 info.virtual_height,
221 info.size
222 );
223 if !uncached {
224 crate::warn!("[GPU] VRAM in cached RAM region (<0x38000000)!");
225 }
226 fb_info = Some(info);
227 break;
228 } else {
229 crate::debug!("[GPU] Mailbox OK but parse failed for {}x{}", w, h);
230 }
231 } else {
232 crate::debug!("[GPU] Mailbox call failed for {}x{}", w, h);
233 }
234 }
235
236 let info = match fb_info {
237 Some(i) => i,
238 None => {
239 crate::error!(
240 "[GPU] FATAL: FrameBuffer allocation failed for all resolutions. Halting."
241 );
242 loop {
243 unsafe {
244 core::arch::asm!("wfe");
245 }
246 }
247 }
248 };
249 crate::println!("{:.<50} [OK]", "1. Graphics System (FrameBuffer)");
250 unsafe {
252 let pitch = if info.pitch == 0 {
253 info.width * 4
254 } else {
255 info.pitch
256 };
257 let screen = Screen::new(info.pointer, info.width, info.height, pitch);
258 CURRENT_SCREEN = Some(screen);
259 kernel::draw::SPLASH_ACTIVE = true;
260 if let Some(ref screen) = CURRENT_SCREEN {
261 screen.clear(kernel::draw::Color(0xFF000000));
262 }
263 }
264
265 let vector_addr = unsafe { &exception_vector_table as *const u8 as usize };
267 unsafe {
268 core::arch::asm!("msr vbar_el1, {}", in(reg) vector_addr);
269 }
270 crate::info!(
271 "[SYS] Exception Vector Table registered at 0x{:016X}",
272 vector_addr
273 );
274
275 kernel::mmu::init();
277
278 if let Err(e) = crate::kernel::v3d::init() {
280 crate::warn!("[V3D] V3D Init Error: {}", e);
281 }
282
283 let heap_start = unsafe { &__cpu_stacks_end as *const u8 as usize };
285 let heap_size = kernel::allocator::KERNEL_HEAP_SIZE;
289 kernel::allocator::init(heap_start, heap_size);
290 crate::info!(
291 "[MEM] Kernel Heap Allocator initialized. (Heap start: 0x{:016X}, Heap size: 512 MB)",
292 heap_start
293 );
294 crate::println!("{:.<50} [OK]", "2. Memory System (MMU & Heap)");
295 unsafe {
297 kernel::draw::draw_splash_logo();
298 }
299
300 #[cfg(feature = "selftest")]
306 {
307 let mut tests_failed = false;
309 kernel::uart::set_silent(true);
310
311 let mut js_ok = false;
312 let mut bigint_ok = false;
313 let mut aura_ok = false;
314 let mut css_ok = false;
315 let mut layout_ok = false;
316 let mut ime_ok = false;
317 let mut cloud_ok = false;
318 let mut h264_ok = false;
319 let mut h264_golden_ok = false;
320 let mut reclock_ok = false;
321 let mut fs_ok = false;
322 let mut usbsched_ok = false;
323
324 let (pass, total) = os_lib::js::selftest();
344 if pass == total {
345 js_ok = true;
346 } else {
347 tests_failed = true;
348 crate::println!("[SELFTEST] JS: {}/{} passed", pass, total);
349 }
350
351 let (pass, total) = os_lib::js::bigint::selftest();
353 if pass == total {
354 bigint_ok = true;
355 } else {
356 tests_failed = true;
357 crate::println!("[SELFTEST] BigInt: {}/{} passed", pass, total);
358 }
359
360 let (pass, total) = os_lib::aura::selftest();
362 if pass == total {
363 aura_ok = true;
364 } else {
365 tests_failed = true;
366 crate::println!("[SELFTEST] Aura: {}/{} passed", pass, total);
367 }
368
369 let (pass, total) = os_lib::css::selftest();
371 if pass == total {
372 css_ok = true;
373 } else {
374 tests_failed = true;
375 crate::println!("[SELFTEST] CSS: {}/{} passed", pass, total);
376 }
377
378 let (pass, total) = os_lib::layout::selftest();
380 if pass == total {
381 layout_ok = true;
382 } else {
383 tests_failed = true;
384 crate::println!("[SELFTEST] Layout: {}/{} passed", pass, total);
385 }
386
387 let (pass, total) = kernel::ime::selftest();
389 if pass == total {
390 ime_ok = true;
391 } else {
392 tests_failed = true;
393 crate::println!("[SELFTEST] IME: {}/{} passed", pass, total);
394 }
395
396 let (pass, total) = os_lib::cloud::selftest();
398 if pass == total {
399 cloud_ok = true;
400 } else {
401 tests_failed = true;
402 crate::println!("[SELFTEST] Cloud: {}/{} passed", pass, total);
403 }
404
405 let (pass, total) = os_lib::h264::selftest();
407 if pass == total {
408 h264_ok = true;
409 } else {
410 tests_failed = true;
411 crate::println!("[SELFTEST] H264: {}/{} passed", pass, total);
412 }
413
414 if os_lib::h264_decode::golden_test() {
416 h264_golden_ok = true;
417 } else {
418 tests_failed = true;
419 crate::println!("[SELFTEST] H264 Golden: failed");
420 }
421
422 if kernel::reclock::selftest() {
424 reclock_ok = true;
425 } else {
426 tests_failed = true;
427 crate::println!("[SELFTEST] Reclock: failed");
428 }
429
430 let (pass, total) = kernel::fs::selftest();
432 if pass == total {
433 fs_ok = true;
434 } else {
435 tests_failed = true;
436 crate::println!("[SELFTEST] FS: {}/{} passed", pass, total);
437 }
438
439 let (pass, total) = kernel::usb::frame_sched::selftest();
441 if pass == total {
442 usbsched_ok = true;
443 } else {
444 tests_failed = true;
445 crate::println!("[SELFTEST] USB Sched: {}/{} passed", pass, total);
446 }
447
448 kernel::uart::set_silent(false);
449
450 let js_str = if js_ok {
451 "JS_SELFTEST: PASS"
452 } else {
453 "JS_SELFTEST: FAIL"
454 };
455 let bigint_str = if bigint_ok {
456 "BIGINT_SELFTEST: PASS"
457 } else {
458 "BIGINT_SELFTEST: FAIL"
459 };
460 let aura_str = if aura_ok {
461 "AURA_SELFTEST: PASS"
462 } else {
463 "AURA_SELFTEST: FAIL"
464 };
465 let css_str = if css_ok {
466 "CSS_SELFTEST: PASS"
467 } else {
468 "CSS_SELFTEST: FAIL"
469 };
470 let layout_str = if layout_ok {
471 "LAYOUT_SELFTEST: PASS"
472 } else {
473 "LAYOUT_SELFTEST: FAIL"
474 };
475 let ime_str = if ime_ok {
476 "IME_SELFTEST: PASS"
477 } else {
478 "IME_SELFTEST: FAIL"
479 };
480 let cloud_str = if cloud_ok {
481 "CLOUD_SELFTEST: PASS"
482 } else {
483 "CLOUD_SELFTEST: FAIL"
484 };
485 let h264_str = if h264_ok {
486 "H264_SELFTEST: PASS"
487 } else {
488 "H264_SELFTEST: FAIL"
489 };
490 let h264_golden_str = if h264_golden_ok {
491 "H264_GOLDEN: PASS"
492 } else {
493 "H264_GOLDEN: FAIL"
494 };
495 let reclock_str = if reclock_ok {
496 "RECLOCK_SELFTEST: PASS"
497 } else {
498 "RECLOCK_SELFTEST: FAIL"
499 };
500 let fs_str = if fs_ok {
501 "FS_SELFTEST: PASS"
502 } else {
503 "FS_SELFTEST: FAIL"
504 };
505 let usbsched_str = if usbsched_ok {
506 "USBSCHED_SELFTEST: PASS"
507 } else {
508 "USBSCHED_SELFTEST: FAIL"
509 };
510
511 if !tests_failed {
512 crate::println!(
514 "3. Core Software Self-Tests ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}) [OK]",
515 js_str,
516 bigint_str,
517 aura_str,
518 css_str,
519 layout_str,
520 ime_str,
521 cloud_str,
522 h264_str,
523 h264_golden_str,
524 reclock_str,
525 fs_str,
526 usbsched_str
527 );
528 } else {
529 crate::println!(
530 "3. Core Software Self-Tests ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}) [FAIL]",
531 js_str,
532 bigint_str,
533 aura_str,
534 css_str,
535 layout_str,
536 ime_str,
537 cloud_str,
538 h264_str,
539 h264_golden_str,
540 reclock_str,
541 fs_str,
542 usbsched_str
543 );
544 loop {
545 unsafe {
546 core::arch::asm!("wfe");
547 }
548 }
549 }
550 } unsafe {
558 if !check_stack_canary() {
559 report_stack_canary_violation("selftest block (main.rs)");
560 }
561 }
562
563 match kernel::fs::mount() {
568 Ok(()) => crate::println!("{:.<50} [OK]", "4. File System (SylFS)"),
569 Err(e) => {
570 crate::error!("[FS] Mount completed with errors: {}", e);
571 crate::println!("{:.<50} [NG] {}", "4. File System (SylFS)", e);
572 }
573 }
574
575 kernel::net::init();
577
578 let pitch = if info.pitch == 0 {
580 info.width * 4
581 } else {
582 info.pitch
583 };
584 let screen = Screen::new(info.pointer, info.width, info.height, pitch);
585 screen.set_fb_geometry(info.virtual_height, info.size);
589 unsafe {
590 CURRENT_SCREEN = Some(screen);
591 }
592 kernel::audio::Audio::init();
593 crate::info!("[GPU] Screen initialization completed!");
594 crate::println!("{:.<50} [OK]", "5. Audio Systems");
595
596 kernel::scheduler::init();
598
599 kernel::scheduler::spawn_on_core(
601 gui_shell_process,
602 kernel::scheduler::Priority::High,
603 "gui_shell",
604 0,
605 );
606
607 crate::info!("[SYS] Initializing Interrupt Controller...");
623 kernel::interrupt::init();
624
625 kernel::timer::init();
627
628 kernel::usb::init();
631
632 kernel::interrupt::enable_interrupts();
633 crate::println!("{:.<50} [OK]", "6. USB Host Controller & HID Stack");
634
635 crate::println!("{:.<50} [OK]", "7. System Scheduler & Interrupts");
636 crate::println!("--------------------------------------------------");
637 crate::println!(" AtmOS OS Base Phase 3 (merged) running!");
638 crate::println!(" Author: SUGIMURA Hiroshi (Sugimura Laboratoly)");
639 crate::println!("--------------------------------------------------");
640 unsafe {
641 kernel::draw::SPLASH_ACTIVE = false;
642 }
643
644 crate::info!("[SYS] Waking up secondary cores...");
645 unsafe {
646 core::ptr::write_volatile(
649 &mut spin_cpu1 as *mut u64,
650 secondary_entry as *const () as u64,
651 );
652 core::ptr::write_volatile(
653 &mut spin_cpu2 as *mut u64,
654 secondary_entry as *const () as u64,
655 );
656 core::ptr::write_volatile(
657 &mut spin_cpu3 as *mut u64,
658 secondary_entry as *const () as u64,
659 );
660
661 core::ptr::write_volatile(0xe0 as *mut u64, secondary_entry as *const () as u64);
663 core::ptr::write_volatile(0xe8 as *mut u64, secondary_entry as *const () as u64);
664 core::ptr::write_volatile(0xf0 as *mut u64, secondary_entry as *const () as u64);
665
666 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
668
669 core::arch::asm!(
671 "dc cvac, {}",
672 "dc cvac, {}",
673 "dc cvac, {}",
674 "dsb sy",
675 in(reg) &spin_cpu1 as *const u64,
676 in(reg) &spin_cpu2 as *const u64,
677 in(reg) &spin_cpu3 as *const u64,
678 );
679
680 core::arch::asm!(
682 "dc cvac, {0}",
683 "dc cvac, {1}",
684 "dc cvac, {2}",
685 "dsb sy",
686 in(reg) 0xe0usize,
687 in(reg) 0xe8usize,
688 in(reg) 0xf0usize,
689 );
690
691 core::arch::asm!("sev");
693 }
694
695 loop {
697 kernel::scheduler::yield_now();
698 }
699}
700
701#[no_mangle]
702pub extern "C" fn secondary_startup() -> ! {
703 let core_id: usize;
704 unsafe {
705 let mpidr: u64;
706 core::arch::asm!("mrs {}, mpidr_el1", out(reg) mpidr);
707 core_id = (mpidr & 0xFF) as usize;
708 }
709 crate::debug!("[SMP] Core {}: secondary_startup entry", core_id);
710
711 let vector_addr = unsafe { &exception_vector_table as *const u8 as usize };
713 unsafe {
714 core::arch::asm!("msr vbar_el1, {}", in(reg) vector_addr);
715 }
716 crate::debug!("[SMP] Core {}: VBAR set", core_id);
717
718 kernel::mmu::init_secondary();
720 crate::debug!("[SMP] Core {}: MMU ready", core_id);
721
722 kernel::interrupt::init_secondary();
724 crate::debug!("[SMP] Core {}: IRQ controller ready", core_id);
725 kernel::timer::init_secondary();
726 crate::debug!("[SMP] Core {}: timer ready", core_id);
727
728 println!("[SMP] Core {} started!", core_id);
730
731 kernel::scheduler::register_idle_process(core_id);
733
734 kernel::interrupt::enable_interrupts();
736
737 loop {
739 kernel::scheduler::yield_now();
740 }
741}
742
743static mut TABLET_MAX_X: u32 = 32768;
745static mut TABLET_MAX_Y: u32 = 32768;
746
747fn usb_poll_thread() {
748 crate::warn!(
749 "USB Poll Thread started on Core {}",
750 crate::kernel::scheduler::core_id()
751 );
752 unsafe {
753 crate::kernel::usb::POLL_THREAD_ACTIVE = true;
754 }
755 let mut divider: u32 = 0;
756 loop {
757 crate::kernel::usb::poll();
758 divider = divider.wrapping_add(1);
759 if divider.is_multiple_of(32) {
760 crate::kernel::net::dhcp_tick();
761 }
762 static mut HEAP_CORRUPTION_FOUND: bool = false;
768 if divider.is_multiple_of(4096)
769 && unsafe { !HEAP_CORRUPTION_FOUND }
770 && crate::kernel::allocator::check_heap_integrity()
771 {
772 unsafe {
773 HEAP_CORRUPTION_FOUND = true;
774 }
775 }
776 let start = crate::kernel::timer::get_system_time_ms();
777 while crate::kernel::timer::get_system_time_ms().wrapping_sub(start) < 8 {
778 unsafe { core::arch::asm!("nop") };
779 }
780 crate::kernel::scheduler::yield_now(); }
782}
783
784fn net_service_thread() {
788 crate::info!(
789 "Net Service Thread started on Core {}",
790 crate::kernel::scheduler::core_id()
791 );
792 let mut ntp_last_attempt_ms: u64 = 0;
793 loop {
794 crate::kernel::usb::poll_ethernet_data_plane_only();
806
807 let net_st = crate::kernel::net::status();
811 if !crate::kernel::timer::is_wall_clock_set() && net_st.link_up && net_st.ip != [0; 4] {
812 let now = crate::kernel::timer::get_system_time_ms();
813 if ntp_last_attempt_ms == 0 || now.wrapping_sub(ntp_last_attempt_ms) > 30_000 {
814 ntp_last_attempt_ms = now;
815 if let Err(e) = crate::kernel::net::ntp_sync() {
816 crate::warn!("[SYS] NTP sync failed: {}", e);
817 }
818 }
819 } else if net_st.ip == [0; 4] {
820 ntp_last_attempt_ms = 0;
822 }
823 crate::kernel::scheduler::sleep(10);
858 }
859}
860
861fn gui_shell_process() {
862 crate::info!(
863 "GUI Shell process has started on Core {}",
864 crate::kernel::scheduler::core_id()
865 );
866 crate::os_lib::svg::init_cache();
867
868 let Some(screen) = (unsafe { CURRENT_SCREEN.as_mut() }) else {
869 crate::println!("GUI Shell: CURRENT_SCREEN is not initialized. Aborting GUI shell.");
870 return;
871 };
872
873 crate::info!("[NET] Initializing WiFi SDIO controller...");
878 if kernel::sdio::init() {
879 crate::info!("[NET] SDIO initialized. Starting WiFi driver...");
880 if kernel::wifi::init() {
881 crate::info!("[NET] WiFi ready.");
882 } else {
883 crate::info!("[NET] WiFi init failed (firmware may be missing from /boot/).");
884 }
885 } else {
886 crate::info!("[NET] SDIO init failed (no WiFi chip detected).");
887 }
888
889 kernel::scheduler::spawn_on_core(
891 usb_poll_thread,
892 kernel::scheduler::Priority::High,
893 "usb_poll",
894 1,
895 );
896
897 kernel::scheduler::spawn_on_core(
901 net_service_thread,
902 kernel::scheduler::Priority::Normal,
903 "net_service",
904 2,
905 );
906
907 let conf = kernel::config::get_config();
910 crate::info!("[GPU] Initializing Vector Font Engine: {:?}...", conf.font_names);
911 let chain: alloc::vec::Vec<&str> = conf.font_names.iter().map(|s| s.as_str()).collect();
912 kernel::vector_font::init_global_font_chain(&chain);
913 kernel::vector_font::init_terminal_font();
914 crate::info!("[GPU] Vector Font initialized successfully!");
915
916 crate::info!("[SYS] Initializing Web Browser...");
918 apps::browser::init();
919 crate::info!("[SYS] Web Browser initialized successfully!");
920
921 crate::info!("[SYS] Initializing Window Manager...");
922 kernel::window_mgr::init();
923 crate::info!("[SYS] Window Manager initialized successfully!");
924
925 crate::info!("[SYS] Initializing Terminal...");
926
927 let loaded_config = crate::kernel::config::init_or_load();
930 if let Err(e) = loaded_config.status {
931 crate::error!(
932 "[SYS] Configuration loaded with errors (defaults were used): {}",
933 e
934 );
935 }
936 let os_config = loaded_config.config;
937 crate::kernel::net::set_dhcp_auto_pending(os_config.auto_dhcp);
938
939 let mut terminal = crate::apps::terminal::Terminal::new();
940
941 let mut mouse_tracker = crate::kernel::mouse_tracker::MouseTracker::new(
942 (screen.width - 16) / 2,
943 (screen.height - 28 - 16) / 2,
944 screen.width,
945 screen.height,
946 );
947 let mut mx = mouse_tracker.x;
948 let mut my = mouse_tracker.y;
949 let mut mouse_obj = kernel::draw::Mouse::new(mx, my);
950
951 let mut shortcut_mgr = crate::kernel::shortcut_manager::ShortcutManager::new();
952 use crate::kernel::shortcut_manager::{InputAction, Modifiers, Shortcut, ShortcutLayer};
953 shortcut_mgr.register(Shortcut::new(
955 0x48,
956 Modifiers::new(false, true, false),
957 ShortcutLayer::OS,
958 InputAction::SwitchTabRelative(-1),
959 )); shortcut_mgr.register(Shortcut::new(
961 0x50,
962 Modifiers::new(false, true, false),
963 ShortcutLayer::OS,
964 InputAction::SwitchTabRelative(1),
965 )); shortcut_mgr.register(Shortcut::new(
967 0x14,
968 Modifiers::new(false, true, false),
969 ShortcutLayer::OS,
970 InputAction::NewTab,
971 )); shortcut_mgr.register(Shortcut::new(
973 0x11,
974 Modifiers::new(false, true, false),
975 ShortcutLayer::OS,
976 InputAction::CloseTab,
977 )); shortcut_mgr.register(Shortcut::new(
979 0x18,
980 Modifiers::new(false, true, false),
981 ShortcutLayer::OS,
982 InputAction::OpenFileDialog,
983 )); shortcut_mgr.register(Shortcut::new(
985 0x1F,
986 Modifiers::new(false, true, false),
987 ShortcutLayer::OS,
988 InputAction::SaveFile,
989 )); shortcut_mgr.register(Shortcut::new(
991 0x01,
992 Modifiers::new(false, false, false),
993 ShortcutLayer::OS,
994 InputAction::ToggleFocusSysmonTerminal,
995 )); let mut kbd = crate::kernel::keyboard::Keyboard::new();
998 kbd.set_layout(os_config.keyboard_layout);
999 let mut mouse_dec = crate::kernel::mouse::MouseDecoder::new();
1000 let mut input_state = 0;
1001 let mut ime_state = crate::kernel::ime::ImeState::new();
1002 ime_state.load_dict();
1005
1006 let mut tablet_btn = 0u32;
1008 let mut tablet_abs_x = 0u32;
1009 let mut tablet_abs_y = 0u32;
1010
1011 let mut login_mgr = crate::apps::login::LoginManager::new();
1012 let _first_unlock = true;
1013
1014 let tab_w = 100;
1016 let sysmon_w = if screen.width >= 1920 { 518 } else { 300 };
1017 let sysmon_x = screen.width - sysmon_w;
1018 let center_w = sysmon_x - tab_w - 2;
1019 let content_h = screen.height.saturating_sub(kernel::fn_bar::BAR_HEIGHT);
1021
1022 let mut sysmon_pane =
1024 kernel::window::SystemMonitorPane::new(sysmon_x as i32 + 2, 0, sysmon_w - 2, content_h);
1025
1026 screen.debug_geometry();
1028 screen.enable_double_buffering();
1029 let vsync_on = screen.enable_vsync();
1031 if vsync_on {
1032 println!("[FB] VSync page-flip ENABLED (double buffer / 2 pages confirmed)");
1033 } else {
1034 println!("[FB] VSync page-flip DISABLED (single buffer; 2 pages not allocated)");
1035 }
1036 let mut last_render_time = crate::kernel::timer::get_system_time_ms();
1037 let mut last_sysmon_ticks = 0;
1038
1039 let mut power_modal_visible = false;
1040 let mut pwr_last_mouse_btn = false;
1041 let mut first_render = true;
1042 let mut was_unlocked = login_mgr.is_unlocked();
1043
1044 crate::warn!("[SYS] === GUI Shell: All initialization complete. Entering main loop ===");
1046 unsafe {
1047 crate::kernel::dialog::GLOBAL_FILE_DIALOG = Some(crate::kernel::dialog::FileDialog::new());
1048 }
1049
1050 loop {
1051 let mut processed_any = false;
1054
1055 loop {
1056 let (kbd_data, mouse_data, uart_data) = {
1057 crate::kernel::interrupt::disable_interrupts();
1058 let kd = crate::kernel::interrupt::KBD_FIFO.lock().pop();
1059 let md = crate::kernel::interrupt::MOUSE_FIFO.lock().pop();
1060 let ud = crate::kernel::interrupt::UART_FIFO.lock().pop();
1061 crate::kernel::interrupt::enable_interrupts();
1062 (kd, md, ud)
1063 };
1064
1065 if kbd_data.is_none() && mouse_data.is_none() && uart_data.is_none() {
1066 break;
1067 }
1068 processed_any = true;
1069
1070 if let Some(byte) = uart_data {
1076 let b = byte as u8;
1077 if b < 0x80 {
1078 let layout = crate::kernel::config::get_config().keyboard_layout;
1079 if let Some((kc, shift)) =
1080 crate::kernel::keyboard::ascii_to_scancode(b as char, layout)
1081 {
1082 let mut seq = [0u8; 4];
1084 let mut n = 0;
1085 if shift {
1086 seq[n] = 0x2A;
1087 n += 1;
1088 } seq[n] = kc;
1090 n += 1; seq[n] = kc | 0x80;
1092 n += 1; if shift {
1094 seq[n] = 0xAA;
1095 n += 1;
1096 } for &sc in &seq[..n] {
1098 if let Some(ev) = kbd.decode(sc) {
1099 process_key_event(
1100 ev,
1101 1,
1102 &mut terminal,
1103 &mut kbd,
1104 &mut ime_state,
1105 &mut login_mgr,
1106 &mut sysmon_pane,
1107 &mut power_modal_visible,
1108 screen,
1109 &shortcut_mgr,
1110 );
1111 }
1112 }
1113 }
1114 }
1115 }
1116
1117 if let Some(data_u32) = mouse_data {
1118 let val = data_u32 as u8;
1119 match input_state {
1120 0 => {
1121 if val == 0xFE {
1122 input_state = 2;
1123 } else if val == 0xFC {
1124 input_state = 5;
1125 }
1126 }
1127
1128 2 => {
1129 let _ = mouse_dec.decode(val);
1130 input_state = 3;
1131 }
1132 3 => {
1133 let _ = mouse_dec.decode(val);
1134 input_state = 4;
1135 }
1136 4 => {
1137 if let Some(mev) = mouse_dec.decode(val) {
1138 mouse_tracker.move_relative(mev.dx, mev.dy);
1139 mx = mouse_tracker.x;
1140 my = mouse_tracker.y;
1141
1142 let left_click = mev.left_btn;
1143 let just_pressed = left_click && !pwr_last_mouse_btn;
1144 pwr_last_mouse_btn = left_click;
1145
1146 if power_modal_visible {
1147 if just_pressed {
1148 let cx = screen.width / 2;
1149 let cy = screen.height / 2;
1150 if mx >= cx - 150 && mx <= cx + 150 {
1151 if my >= cy - 60 && my <= cy - 20 {
1152 unsafe {
1154 screen.clear(kernel::draw::Color::BLACK);
1155 screen.draw_string_vector(cx.saturating_sub(250), cy - 10, "System Halted. You can safely turn off your machine.", kernel::draw::Color::WHITE, 24);
1156 screen.flush();
1157 loop {
1158 core::arch::asm!("wfe");
1159 }
1160 }
1161 } else if my >= cy && my <= cy + 40 {
1162 unsafe {
1164 let rstc = 0x3F10_001C as *mut u32;
1165 let wdog = 0x3F10_0024 as *mut u32;
1166 core::ptr::write_volatile(wdog, 0x5A00_0000 | 10);
1167 let mut rstc_val = core::ptr::read_volatile(rstc);
1168 rstc_val = (rstc_val & 0xFFFF_FFCF) | 0x5A00_0020;
1169 core::ptr::write_volatile(rstc, rstc_val);
1170 loop {
1171 core::arch::asm!("wfe");
1172 }
1173 }
1174 } else if my >= cy + 60 && my <= cy + 100 {
1175 power_modal_visible = false;
1177 let mut wm = kernel::window_mgr::get_instance();
1178 wm.dirty = true;
1179 }
1180 }
1181 }
1182 } else {
1183 let mut wm_handled = false;
1184 if login_mgr.is_unlocked() {
1185 let mut wm = kernel::window_mgr::get_instance();
1186 wm_handled = wm.handle_mouse(
1187 mx as i32,
1188 my as i32,
1189 left_click,
1190 mev.right_btn,
1191 0,
1192 screen,
1193 );
1194 if wm.terminal_focused && just_pressed {
1196 if let Some(app_name) = terminal.handle_click(mx as i32, my as i32) {
1197 let cmd = alloc::format!("os.run(\"{}\")", app_name);
1198 if let Some(ctx) = &terminal.context {
1199 ctx.cmd_queue.push(cmd);
1200 }
1201 terminal.print_line(alloc::format!("> run {}", app_name));
1202 terminal.dirty = true;
1203 wm.dirty = true;
1204 }
1205 }
1206 }
1207
1208 if wm_handled {
1209 sysmon_pane.handle_mouse(-1, -1, left_click);
1210 } else {
1211 let sysmon_handled =
1212 sysmon_pane.handle_mouse(mx as i32, my as i32, left_click);
1213 if sysmon_pane.wants_power_menu {
1214 power_modal_visible = true;
1215 sysmon_pane.wants_power_menu = false;
1216 let mut wm = kernel::window_mgr::get_instance();
1217 wm.dirty = true;
1218 }
1219 if !sysmon_handled && !login_mgr.is_unlocked() {
1220 login_mgr.handle_mouse_input(mx, my, left_click, 0);
1221 }
1222 }
1223 }
1224 }
1225 input_state = 0;
1226 }
1227 5 => {
1228 tablet_btn = data_u32;
1229 input_state = 6;
1230 }
1231 6 => {
1232 tablet_abs_x = data_u32;
1233 input_state = 7;
1234 }
1235 7 => {
1236 tablet_abs_y = data_u32;
1237 input_state = 8;
1238 }
1239 8 => {
1240 let tablet_wheel = data_u32 as i8 as i32;
1241 mouse_tracker.move_absolute_tablet(
1242 tablet_abs_x,
1243 tablet_abs_y,
1244 unsafe { TABLET_MAX_X },
1245 unsafe { TABLET_MAX_Y },
1246 );
1247 mx = mouse_tracker.x;
1248 my = mouse_tracker.y;
1249
1250 let left_click = (tablet_btn & 0x01) != 0;
1251 let right_click = (tablet_btn & 0x02) != 0;
1252 let just_pressed = left_click && !pwr_last_mouse_btn;
1253 pwr_last_mouse_btn = left_click;
1254
1255 let mut dialog_handled = false;
1256 unsafe {
1257 if let Some(ref mut d) = crate::kernel::dialog::GLOBAL_FILE_DIALOG {
1258 if d.is_open {
1259 d.handle_mouse(
1260 mx as i32,
1261 my as i32,
1262 left_click,
1263 screen.width,
1264 screen.height,
1265 );
1266 dialog_handled = true;
1267 }
1268 }
1269 }
1270 if dialog_handled {
1271 kernel::window_mgr::get_instance().dirty = true;
1272 } else if power_modal_visible {
1273 if just_pressed {
1274 let cx = screen.width / 2;
1275 let cy = screen.height / 2;
1276 if mx >= cx - 150 && mx <= cx + 150 {
1277 if my >= cy - 60 && my <= cy - 20 {
1278 unsafe {
1279 screen.clear(kernel::draw::Color::BLACK);
1280 screen.draw_string_vector(cx.saturating_sub(250), cy - 10, "System Halted. You can safely turn off your machine.", kernel::draw::Color::WHITE, 24);
1281 screen.flush();
1282 loop {
1283 core::arch::asm!("wfe");
1284 }
1285 }
1286 } else if my >= cy && my <= cy + 40 {
1287 unsafe {
1289 let rstc = 0x3F10_001C as *mut u32;
1290 let wdog = 0x3F10_0024 as *mut u32;
1291 core::ptr::write_volatile(wdog, 0x5A00_0000 | 10);
1292 let mut rstc_val = core::ptr::read_volatile(rstc);
1293 rstc_val = (rstc_val & 0xFFFF_FFCF) | 0x5A00_0020;
1294 core::ptr::write_volatile(rstc, rstc_val);
1295 loop {
1296 core::arch::asm!("wfe");
1297 }
1298 }
1299 } else if my >= cy + 60 && my <= cy + 100 {
1300 power_modal_visible = false;
1301 let mut wm = kernel::window_mgr::get_instance();
1302 wm.dirty = true;
1303 }
1304 }
1305 }
1306 } else {
1307 let mut wm_handled = false;
1308 if login_mgr.is_unlocked() {
1309 let mut wm = kernel::window_mgr::get_instance();
1310 wm_handled = wm.handle_mouse(
1311 mx as i32,
1312 my as i32,
1313 left_click,
1314 right_click,
1315 tablet_wheel,
1316 screen,
1317 );
1318 if wm.terminal_focused && tablet_wheel != 0 {
1319 terminal.scroll(tablet_wheel * 2);
1320 }
1321 if wm.terminal_focused && just_pressed {
1323 if let Some(app_name) = terminal.handle_click(mx as i32, my as i32) {
1324 let cmd = alloc::format!("os.run(\"{}\")", app_name);
1325 if let Some(ctx) = &terminal.context {
1326 ctx.cmd_queue.push(cmd);
1327 }
1328 terminal.print_line(alloc::format!("> run {}", app_name));
1329 terminal.dirty = true;
1330 wm.dirty = true;
1331 }
1332 }
1333 }
1334
1335 if wm_handled {
1336 sysmon_pane.handle_mouse(-1, -1, left_click);
1337 } else {
1338 let sysmon_handled =
1339 sysmon_pane.handle_mouse(mx as i32, my as i32, left_click);
1340 if sysmon_pane.wants_power_menu {
1341 power_modal_visible = true;
1342 sysmon_pane.wants_power_menu = false;
1343 let mut wm = kernel::window_mgr::get_instance();
1344 wm.dirty = true;
1345 }
1346 if !sysmon_handled && !login_mgr.is_unlocked() {
1347 login_mgr.handle_mouse_input(mx, my, left_click, tablet_wheel);
1348 }
1349 }
1350 }
1351 input_state = 0;
1352 }
1353 _ => input_state = 0,
1354 }
1355 }
1356
1357 if let Some(kbd_u32) = kbd_data {
1358 let val = kbd_u32 as u8;
1359 {
1364 static KEY_TRACE: core::sync::atomic::AtomicU32 =
1365 core::sync::atomic::AtomicU32::new(0);
1366 if KEY_TRACE.fetch_add(1, core::sync::atomic::Ordering::Relaxed) < 64 {
1367 crate::warn!(
1368 "[KBD][TRACE] raw=0x{:02X} make={} code=0x{:02X}",
1369 val,
1370 (val & 0x80) == 0,
1371 val & 0x7F
1372 );
1373 }
1374 }
1375 if let Some(ev) = kbd.decode(val) {
1376 process_key_event(
1377 ev,
1378 1,
1379 &mut terminal,
1380 &mut kbd,
1381 &mut ime_state,
1382 &mut login_mgr,
1383 &mut sysmon_pane,
1384 &mut power_modal_visible,
1385 screen,
1386 &shortcut_mgr,
1387 );
1388
1389 match ev.keycode {
1391 0x1D | 0x38 | 0x2A | 0x36 => {
1392 kernel::window_mgr::get_instance().dirty = true;
1393 }
1394 _ => {}
1395 }
1396
1397 unsafe {
1398 if ev.pressed {
1399 if REPEAT_STATE.active_keycode != ev.keycode {
1400 REPEAT_STATE.active_keycode = ev.keycode;
1401 let now = kernel::timer::get_system_time_ms();
1402 REPEAT_STATE.press_start_ms = now;
1403 REPEAT_STATE.last_repeat_ms = now;
1404 REPEAT_STATE.stage = 0;
1405 }
1406 } else {
1407 if REPEAT_STATE.active_keycode == ev.keycode {
1408 REPEAT_STATE.active_keycode = 0;
1409 }
1410 }
1411 }
1412 }
1413 }
1414 }
1415
1416 if !processed_any {
1417 let mut key_event_to_process: Option<kernel::keyboard::KeyEvent> = None;
1419 let mut repeat_count: u32 = 1;
1420 unsafe {
1421 if REPEAT_STATE.active_keycode != 0 {
1422 let now = kernel::timer::get_system_time_ms();
1423 let elapsed = now.saturating_sub(REPEAT_STATE.press_start_ms);
1424 let since_last_repeat = now.saturating_sub(REPEAT_STATE.last_repeat_ms);
1425
1426 if elapsed >= REPEAT_PARAMS.second_delay_ms as u64 {
1428 if since_last_repeat >= REPEAT_PARAMS.second_interval_ms as u64 {
1429 REPEAT_STATE.stage = 2;
1430 REPEAT_STATE.last_repeat_ms = now;
1431 key_event_to_process = Some(kernel::keyboard::KeyEvent {
1432 keycode: REPEAT_STATE.active_keycode,
1433 pressed: true,
1434 });
1435 repeat_count = REPEAT_PARAMS.second_repeat_count;
1436 }
1437 }
1438 else if elapsed >= REPEAT_PARAMS.first_delay_ms as u64
1440 && since_last_repeat >= REPEAT_PARAMS.first_interval_ms as u64
1441 {
1442 REPEAT_STATE.stage = 1;
1443 REPEAT_STATE.last_repeat_ms = now;
1444 key_event_to_process = Some(kernel::keyboard::KeyEvent {
1445 keycode: REPEAT_STATE.active_keycode,
1446 pressed: true,
1447 });
1448 repeat_count = 1;
1449 }
1450 }
1451 }
1452
1453 if let Some(ev) = key_event_to_process {
1454 process_key_event(
1455 ev,
1456 repeat_count,
1457 &mut terminal,
1458 &mut kbd,
1459 &mut ime_state,
1460 &mut login_mgr,
1461 &mut sysmon_pane,
1462 &mut power_modal_visible,
1463 screen,
1464 &shortcut_mgr,
1465 );
1466 }
1467
1468 let ticks = crate::kernel::timer::get_ticks();
1469 static mut NIC_DEBUG_DONE: bool = false;
1470 if ticks == 500 && unsafe { !NIC_DEBUG_DONE } {
1471 unsafe {
1472 NIC_DEBUG_DONE = true;
1473 }
1474 crate::info!("[NET] === HEADLESS 5 SEC NIC DEBUG ===");
1475 crate::info!("[NET] {}", crate::kernel::net::nic_debug_info());
1476 crate::info!("[NET] === END NIC DEBUG ===");
1477 }
1478
1479 crate::kernel::scheduler::yield_now();
1480 }
1481
1482 let now = crate::kernel::timer::get_system_time_ms();
1486 if now.saturating_sub(last_render_time) >= 16 {
1487 last_render_time = now;
1488
1489 let mouse_moved = mx != mouse_obj.x || my != mouse_obj.y;
1490
1491 let was_clicked = mouse_obj.is_clicked;
1493 mouse_obj.is_clicked = pwr_last_mouse_btn;
1494 if pwr_last_mouse_btn {
1495 if !was_clicked {
1496 mouse_obj.click_frame = 1;
1498 } else if mouse_obj.click_frame < 10 {
1499 mouse_obj.click_frame += 1;
1500 }
1501 } else {
1502 mouse_obj.click_frame = 0;
1503 }
1504 let mouse_animating = mouse_obj.click_frame > 0 && mouse_obj.click_frame < 10;
1505
1506 mouse_obj.is_text_cursor = apps::browser::hovered_cursor_is_text();
1510
1511 let now_ticks = crate::kernel::timer::get_ticks();
1512 let sysmon_needs_update = now_ticks.saturating_sub(last_sysmon_ticks) >= 1000;
1513 let timer_redraw = kernel::window_mgr::get_instance().needs_timer_redraw();
1514 let browser_active_render = apps::browser::needs_render();
1515
1516 let mut wm = kernel::window_mgr::get_instance();
1518
1519 let is_unlocked = login_mgr.is_unlocked();
1524 if is_unlocked && !was_unlocked {
1525 wm.add_dirty_rect(kernel::window_mgr::Rect::new(
1526 0,
1527 0,
1528 screen.width,
1529 screen.height,
1530 ));
1531 was_unlocked = true;
1532 }
1533
1534 if !is_unlocked {
1535 if login_mgr.needs_redraw || first_render {
1536 wm.add_dirty_rect(kernel::window_mgr::Rect::new(
1537 0,
1538 0,
1539 screen.width,
1540 screen.height,
1541 ));
1542 }
1543 } else {
1544 if terminal.has_pending_results() {
1547 terminal.dirty = true;
1548 }
1549 if terminal.dirty || terminal.input_dirty {
1550 wm.add_dirty_rect(kernel::window_mgr::Rect::new(
1552 0,
1553 0,
1554 tab_w + center_w,
1555 content_h,
1556 ));
1557 }
1558 if sysmon_needs_update {
1559 wm.add_dirty_rect(kernel::window_mgr::Rect::new(
1561 sysmon_x as i32,
1562 0,
1563 sysmon_w,
1564 content_h,
1565 ));
1566 }
1567 if wm.dirty {
1568 let rects: alloc::vec::Vec<_> = wm
1570 .windows
1571 .iter()
1572 .filter(|win| win.workspace == wm.active_workspace && !win.is_minimized)
1573 .map(|win| {
1574 kernel::window_mgr::Rect::new(win.x, win.y, win.width, win.height)
1575 })
1576 .collect();
1577 for r in rects {
1578 wm.add_dirty_rect(r);
1579 }
1580 }
1581 {
1584 let rects: alloc::vec::Vec<_> = wm
1585 .windows
1586 .iter()
1587 .filter(|win| {
1588 win.workspace == wm.active_workspace
1589 && !win.is_minimized
1590 && win.app.get_buffer_updated_flag()
1591 .map(|flag| {
1592 flag.swap(false, core::sync::atomic::Ordering::Acquire)
1594 })
1595 .unwrap_or(false)
1596 })
1597 .map(|win| {
1598 kernel::window_mgr::Rect::new(win.x, win.y, win.width, win.height)
1599 })
1600 .collect();
1601 for r in rects {
1602 wm.add_dirty_rect(r);
1603 }
1604 }
1605 if timer_redraw {
1606 let rects: alloc::vec::Vec<_> = wm
1608 .windows
1609 .iter()
1610 .filter(|win| {
1611 win.workspace == wm.active_workspace
1612 && !win.is_minimized
1613 && win.app.needs_timer_redraw()
1614 })
1615 .map(|win| {
1616 kernel::window_mgr::Rect::new(win.x, win.y, win.width, win.height)
1617 })
1618 .collect();
1619 for r in rects {
1620 wm.add_dirty_rect(r);
1621 }
1622 }
1623 if browser_active_render {
1624 let rects: alloc::vec::Vec<_> = wm
1626 .windows
1627 .iter()
1628 .filter(|win| {
1629 win.workspace == wm.active_workspace
1630 && !win.is_minimized
1631 && (win.app.name() == "Browser" || win.app.name() == "WebBrowser")
1632 })
1633 .map(|win| {
1634 kernel::window_mgr::Rect::new(win.x, win.y, win.width, win.height)
1635 })
1636 .collect();
1637 for r in rects {
1638 wm.add_dirty_rect(r);
1639 }
1640 }
1641 if ime_state.mode == crate::kernel::ime::ImeMode::Japanese && ime_state.composing {
1642 let y = screen.height.saturating_sub(44);
1644 wm.add_dirty_rect(kernel::window_mgr::Rect::new(
1645 0,
1646 y as i32 - 250,
1647 screen.width,
1648 300u32,
1649 ));
1650 }
1651 if power_modal_visible {
1652 let cx = screen.width / 2;
1653 let cy = screen.height / 2;
1654 wm.add_dirty_rect(kernel::window_mgr::Rect::new(
1655 cx as i32 - 180,
1656 cy as i32 - 110,
1657 360u32,
1658 220u32,
1659 ));
1660 }
1661 }
1662
1663 if first_render {
1664 wm.add_dirty_rect(kernel::window_mgr::Rect::new(
1665 0,
1666 0,
1667 screen.width,
1668 screen.height,
1669 ));
1670 }
1671 first_render = false;
1672
1673 {
1682 static LAST: core::sync::atomic::AtomicUsize =
1683 core::sync::atomic::AtomicUsize::new(0);
1684 let n = wm.dirty_rects.len();
1685 if n > 0 {
1686 let c = LAST.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
1687 if c < 4 || c.is_multiple_of(25) {
1691 let mut s = alloc::string::String::new();
1692 for r in wm.dirty_rects.iter().take(6) {
1693 s.push_str(&alloc::format!("({},{} {}x{}) ", r.x, r.y, r.w, r.h));
1694 }
1695 }
1696 }
1697 }
1698 let dirty_bb = wm.get_dirty_bounding_box(screen.width, screen.height);
1699
1700 if let Some(rect) = dirty_bb {
1701 screen.set_clip(
1703 rect.x as u32,
1704 rect.y as u32,
1705 (rect.x + rect.w as i32) as u32,
1706 (rect.y + rect.h as i32) as u32,
1707 );
1708
1709 if !login_mgr.is_unlocked() {
1710 screen.clear(kernel::draw::Color::BLACK);
1711 login_mgr.draw(screen);
1712 } else {
1713 let config = crate::kernel::config::get_config();
1714 screen.clear(kernel::draw::Color(config.theme.desktop_bg));
1715 screen.boxfill(
1716 sysmon_x,
1717 0,
1718 sysmon_x + 1,
1719 content_h - 1,
1720 kernel::draw::Color(config.theme.active_window_border),
1721 );
1722 terminal.draw(screen, tab_w as i32, 0, center_w, content_h);
1723
1724 screen.boxfill(0, 0, 100, content_h, kernel::draw::Color(config.theme.tab_area_bg));
1726 screen.boxfill(99, 0, 100, content_h, kernel::draw::Color(config.theme.tab_area_border)); screen.draw_string_vector(10, 15, "TABS", kernel::draw::Color(config.theme.tab_inactive_fg), 14);
1728 screen.boxfill(10, 35, 90, 36, kernel::draw::Color(config.theme.tab_area_border));
1729
1730 let tab_bg = kernel::draw::Color(config.theme.tab_active_bg); let tab_fg = kernel::draw::Color(config.theme.tab_active_fg); screen.boxfill(5, 45, 95, 73, tab_bg);
1733 screen.draw_string_vector(10, 51, "[1]", tab_fg, 12);
1734 screen.draw_string_vector(35, 51, "Shell", tab_fg, 10);
1735 sysmon_pane.draw(screen);
1736 wm.draw_all(screen);
1737
1738 if ime_state.mode == crate::kernel::ime::ImeMode::Japanese
1739 && ime_state.composing
1740 {
1741 let text = if ime_state.converting {
1742 alloc::format!(" {} ", ime_state.get_display_text())
1743 } else {
1744 alloc::format!(" {}_{} ", ime_state.kana_buf, ime_state.romaji_buf)
1745 };
1746 let text_px: u32 = text
1748 .chars()
1749 .map(|c| if (c as u32) > 127 { 16u32 } else { 9u32 })
1750 .sum();
1751 let w = (text_px + 24).clamp(60, sysmon_x.saturating_sub(20));
1752 let h = 30u32;
1753 let x = sysmon_x.saturating_sub(w + 20);
1755 let y = screen.height.saturating_sub(44);
1756 screen.boxfill(x, y, x + w, y + h, kernel::draw::Color(config.theme.ime_bg));
1757
1758 let line_color = kernel::draw::Color(config.theme.ime_border);
1759 screen.boxfill(x, y, x + w, y + 2, line_color);
1760 screen.draw_string_vector(
1761 x + 10,
1762 y + 7,
1763 &text,
1764 kernel::draw::Color(config.theme.ime_text),
1765 16,
1766 );
1767
1768 if ime_state.converting && !ime_state.candidates.is_empty() {
1770 let c_w = 220u32;
1771 let c_h = ime_state.candidates.len() as u32 * 25 + 10;
1772 let c_x_right = x + w;
1773 let c_x = c_x_right.saturating_sub(c_w);
1774 let c_y = if y >= c_h + 5 { y - c_h - 5 } else { 0 };
1775 let max_rows = ((y.saturating_sub(c_y)) / 25).max(1) as usize;
1776 let visible_cands = ime_state.candidates.len().min(max_rows);
1777
1778 screen.boxfill(
1779 c_x,
1780 c_y,
1781 c_x + c_w,
1782 c_y + visible_cands as u32 * 25 + 10,
1783 kernel::draw::Color(config.theme.ime_bg),
1784 );
1785 screen.boxfill(
1786 c_x,
1787 c_y,
1788 c_x + c_w,
1789 c_y + 2,
1790 kernel::draw::Color(config.theme.ime_border),
1791 );
1792
1793 for (i, cand) in
1794 ime_state.candidates.iter().enumerate().take(visible_cands)
1795 {
1796 let item_y = c_y + 5 + (i as u32 * 25);
1797 if i == ime_state.selected_idx {
1798 screen.boxfill(
1799 c_x + 2,
1800 item_y,
1801 c_x + c_w - 2,
1802 item_y + 24,
1803 kernel::draw::Color(config.theme.tab_area_border),
1804 );
1805 }
1806 let disp = alloc::format!("{}. {}", i + 1, cand);
1807 screen.draw_string_vector(
1808 c_x + 12,
1809 item_y + 5,
1810 &disp,
1811 kernel::draw::Color(config.theme.ime_text),
1812 14,
1813 );
1814 }
1815 }
1816 }
1817
1818 if sysmon_needs_update {
1819 last_sysmon_ticks = now_ticks;
1820 }
1821
1822 if power_modal_visible {
1823 let cx = screen.width / 2;
1824 let cy = screen.height / 2;
1825
1826 let mw = 360;
1828 let mh = 220;
1829 let mx0 = cx - mw / 2;
1830 let my0 = cy - mh / 2;
1831 screen.boxfill(
1832 mx0,
1833 my0,
1834 mx0 + mw,
1835 my0 + mh,
1836 kernel::draw::Color(config.theme.login_dialog_bg),
1837 );
1838 screen.boxfill(
1839 mx0,
1840 my0,
1841 mx0 + mw,
1842 my0 + 3,
1843 kernel::draw::Color(config.theme.focus_highlight),
1844 ); screen.draw_string_vector(
1846 mx0 + 20,
1847 my0 + 15,
1848 "Power Options",
1849 kernel::draw::Color(config.theme.login_text_fg),
1850 20,
1851 );
1852
1853 screen.boxfill(
1855 cx - 150,
1856 cy - 60,
1857 cx + 150,
1858 cy - 20,
1859 kernel::draw::Color(config.theme.focus_highlight),
1860 );
1861 screen.draw_string_vector(
1862 cx - 45,
1863 cy - 52,
1864 "Shutdown",
1865 kernel::draw::Color::WHITE,
1866 16,
1867 );
1868
1869 screen.boxfill(
1871 cx - 150,
1872 cy,
1873 cx + 150,
1874 cy + 40,
1875 kernel::draw::Color(config.theme.button_active_bg),
1876 );
1877 screen.draw_string_vector(
1878 cx - 35,
1879 cy + 8,
1880 "Reboot",
1881 kernel::draw::Color::WHITE,
1882 16,
1883 );
1884
1885 screen.boxfill(
1887 cx - 150,
1888 cy + 60,
1889 cx + 150,
1890 cy + 100,
1891 kernel::draw::Color(config.theme.button_bg),
1892 );
1893 screen.draw_string_vector(
1894 cx - 35,
1895 cy + 68,
1896 "Cancel",
1897 kernel::draw::Color(config.theme.button_fg),
1898 16,
1899 );
1900 }
1901 }
1902
1903 let mods = kernel::fn_bar::ModState {
1905 ctrl: kbd.ctrl_pressed,
1906 alt: kbd.alt_pressed,
1907 shift: kbd.shift_pressed,
1908 };
1909 kernel::fn_bar::draw(screen, mods);
1910
1911 screen.clear_clip();
1913 }
1914
1915 let has_content_change = dirty_bb.is_some();
1919 let need_vsync_sync = screen.vsync_enabled() && screen.has_pending_vsync_sync();
1920 if has_content_change || mouse_moved || mouse_animating || need_vsync_sync {
1921 if screen.vsync_enabled() {
1922 if mouse_moved || mouse_animating {
1924 mouse_obj.move_to(screen, mx, my);
1925 }
1926 let content = dirty_bb.map(|r| {
1927 (
1928 r.x.max(0) as u32,
1929 r.y.max(0) as u32,
1930 (r.x + r.w as i32).max(0) as u32,
1931 (r.y + r.h as i32).max(0) as u32,
1932 )
1933 });
1934 screen.flush_dirty_pageflip(content, &mouse_obj);
1935 } else {
1936 if mouse_moved || mouse_animating {
1941 let clear_pad = 8;
1943 screen.flush_rect(
1944 mouse_obj.x.saturating_sub(clear_pad),
1945 mouse_obj.y.saturating_sub(clear_pad),
1946 mouse_obj.x + kernel::draw::Mouse::SIZE + clear_pad * 2,
1947 mouse_obj.y + kernel::draw::Mouse::SIZE + clear_pad * 2,
1948 );
1949 }
1950
1951 if let Some(rect) = dirty_bb {
1953 screen.flush_rect(
1954 rect.x as u32,
1955 rect.y as u32,
1956 (rect.x + rect.w as i32) as u32,
1957 (rect.y + rect.h as i32) as u32,
1958 );
1959 }
1960
1961 if mouse_moved {
1963 mouse_obj.move_to(screen, mx, my);
1964 }
1965 screen.draw_mouse_direct(&mouse_obj);
1966 }
1967 }
1968
1969 wm.clear_dirty_rects();
1971 }
1972
1973 crate::kernel::scheduler::yield_now();
1978 }
1979}
1980
1981fn process_key_event(
1982 ev: kernel::keyboard::KeyEvent,
1983 repeat_count: u32,
1984 terminal: &mut crate::apps::terminal::Terminal,
1985 kbd: &mut crate::kernel::keyboard::Keyboard,
1986 ime_state: &mut crate::kernel::ime::ImeState,
1987 login_mgr: &mut crate::apps::login::LoginManager,
1988 sysmon_pane: &mut kernel::window::SystemMonitorPane,
1989 _power_modal_visible: &mut bool,
1990 screen: &kernel::draw::Screen,
1991 shortcut_mgr: &crate::kernel::shortcut_manager::ShortcutManager,
1992) {
1993 for _ in 0..repeat_count {
1994 let mut wm = kernel::window_mgr::get_instance();
1995 let active_ws = wm.active_workspace;
1996
1997 if ev.keycode == 0x01 && ev.pressed {
1999 if ime_state.composing {
2000 ime_state.clear();
2001 kernel::window_mgr::get_instance().dirty = true;
2002 continue;
2003 }
2004 if !apps::browser::is_active() {
2005 if wm.active_workspace != 1 {
2006 wm.active_workspace = 1;
2007 sysmon_pane.focused = true;
2008 wm.terminal_focused = false;
2009 } else {
2010 if sysmon_pane.focused {
2011 sysmon_pane.focused = false;
2012 wm.terminal_focused = true;
2013 } else {
2014 sysmon_pane.focused = true;
2015 wm.terminal_focused = false;
2016 }
2017 }
2018 wm.dirty = true;
2019 crate::kernel::audio::play_system_se(crate::kernel::audio::SeType::Apply);
2020 continue;
2021 }
2022 }
2023
2024 if ev.keycode == 0x38 {
2026 if kbd.ctrl_pressed {
2027 wm.alt_hold_mode = false;
2029 wm.alt_input_buffer.clear();
2030 } else {
2031 if ev.pressed {
2032 wm.alt_hold_mode = true;
2033 wm.alt_input_buffer.clear();
2034 wm.dirty = true;
2035 } else {
2036 wm.alt_hold_mode = false;
2037 if !wm.alt_input_buffer.is_empty() {
2038 if let Ok(target_tab_1based) = wm.alt_input_buffer.parse::<usize>() {
2039 let target_idx = target_tab_1based.saturating_sub(1);
2040 if let Some(win) = wm.windows.last_mut() {
2041 if win.workspace == active_ws && !win.is_minimized {
2042 win.app.switch_tab(target_idx);
2043 wm.dirty = true;
2044 }
2045 }
2046 }
2047 wm.alt_input_buffer.clear();
2048 }
2049 wm.dirty = true;
2050 }
2051 }
2052 if !kbd.ctrl_pressed {
2053 continue; }
2055 }
2056
2057 if wm.alt_hold_mode && ev.pressed {
2059 if ev.keycode == 0x0E {
2060 wm.alt_input_buffer.pop();
2062 wm.dirty = true;
2063 continue;
2064 } else if ev.keycode == 0x01 {
2065 wm.alt_input_buffer.clear();
2067 wm.dirty = true;
2068 continue;
2069 } else if let Some(c) = kbd.get_ascii(ev.keycode) {
2070 if c.is_ascii_digit() {
2071 if wm.alt_input_buffer.len() < 2 {
2072 wm.alt_input_buffer.push(c);
2073 wm.dirty = true;
2074 }
2075 continue;
2076 }
2077 }
2078 }
2079
2080 if ev.pressed {
2082 let mods = crate::kernel::shortcut_manager::Modifiers::new(
2083 kbd.ctrl_pressed,
2084 kbd.alt_pressed,
2085 kbd.shift_pressed,
2086 );
2087 let action = shortcut_mgr.evaluate(ev.keycode, mods);
2088
2089 match action {
2090 crate::kernel::shortcut_manager::InputAction::SwitchTabRelative(offset) => {
2091 if let Some(win) = wm.windows.last_mut() {
2092 if win.workspace == active_ws && !win.is_minimized {
2093 let total_tabs = win.app.tabs().len();
2094 if total_tabs > 0 {
2095 let cur_tab = win.app.active_tab() as isize;
2096 let next_tab =
2097 (cur_tab + offset).rem_euclid(total_tabs as isize) as usize;
2098 win.app.switch_tab(next_tab);
2099 wm.dirty = true;
2100 }
2101 }
2102 }
2103 continue;
2104 }
2105 crate::kernel::shortcut_manager::InputAction::NewTab => {
2106 if !wm.terminal_focused {
2107 if let Some(win) = wm.windows.last_mut() {
2108 if win.workspace == active_ws && !win.is_minimized {
2109 let new_tab_idx = win.app.tabs().len();
2110 win.app.add_tab();
2111 win.spawn_tab_thread(new_tab_idx);
2112 wm.dirty = true;
2113 crate::kernel::audio::play_system_se(
2114 crate::kernel::audio::SeType::Apply,
2115 );
2116 }
2117 }
2118 }
2119 continue;
2120 }
2121 crate::kernel::shortcut_manager::InputAction::CloseTab => {
2122 if !wm.terminal_focused {
2123 if let Some(win) = wm.windows.last_mut() {
2124 if win.workspace == active_ws && !win.is_minimized {
2125 let active_idx = win.app.active_tab();
2126 let should_close_window = win.app.close_tab(active_idx);
2127
2128 if should_close_window {
2129 wm.windows.pop();
2130 crate::kernel::audio::play_system_se(
2131 crate::kernel::audio::SeType::Close,
2132 );
2133 if wm.windows.is_empty() {
2134 wm.terminal_focused = true;
2135 }
2136 } else {
2137 crate::kernel::audio::play_system_se(
2138 crate::kernel::audio::SeType::Apply,
2139 );
2140 }
2141 wm.dirty = true;
2142 }
2143 }
2144 }
2145 continue;
2146 }
2147
2148 crate::kernel::shortcut_manager::InputAction::OpenFileDialog => {
2149 if !wm.terminal_focused {
2150 if let Some(win) = wm.windows.last_mut() {
2151 if win.workspace == active_ws && !win.is_minimized {
2152 win.app.open_file_dialog();
2153 wm.dirty = true;
2154 }
2155 }
2156 }
2157 continue;
2158 }
2159
2160 crate::kernel::shortcut_manager::InputAction::SaveFile => {
2161 if !wm.terminal_focused {
2162 if let Some(win) = wm.windows.last_mut() {
2163 if win.workspace == active_ws && !win.is_minimized {
2164 win.app.save_file();
2165 wm.dirty = true;
2166 }
2167 }
2168 }
2169 continue;
2170 }
2171
2172 crate::kernel::shortcut_manager::InputAction::ToggleFocusSysmonTerminal => {
2173 if sysmon_pane.focused {
2174 sysmon_pane.focused = false;
2175 wm.terminal_focused = true;
2176 } else {
2177 sysmon_pane.focused = true;
2178 wm.terminal_focused = false;
2179 }
2180 wm.dirty = true;
2181 crate::kernel::audio::play_system_se(crate::kernel::audio::SeType::Apply);
2182 continue;
2183 }
2184 _ => {}
2185 }
2186 }
2187 if ev.pressed {
2189 if ev.keycode == 0x39 && kbd.ctrl_pressed {
2209 let to_japanese = ime_state.mode != crate::kernel::ime::ImeMode::Japanese;
2210 ime_state.toggle_mode(to_japanese);
2211 kernel::window_mgr::get_instance().dirty = true;
2212 continue;
2213 }
2214 if ev.keycode == 0x79 || ev.keycode == 0x70 || ev.keycode == 0x77 {
2217 ime_state.toggle_mode(true);
2219 kernel::window_mgr::get_instance().dirty = true;
2220 continue;
2221 } else if ev.keycode == 0x7B {
2222 ime_state.toggle_mode(false);
2224 kernel::window_mgr::get_instance().dirty = true;
2225 continue;
2226 }
2227
2228 if ime_state.mode == crate::kernel::ime::ImeMode::Japanese {
2229 let mut wm = kernel::window_mgr::get_instance();
2230 if ev.keycode == 0x0E {
2231 if ime_state.composing {
2233 ime_state.backspace();
2234 wm.dirty = true;
2235 continue;
2236 }
2237 } else if ev.keycode == 0x1C {
2238 if let Some(text) = ime_state.handle_enter() {
2240 for c in text.chars() {
2241 wm.handle_key(0, true, Some(c), false, screen);
2242 }
2243 wm.dirty = true;
2244 continue;
2245 }
2246 } else if ev.keycode == 0x39 {
2247 if ime_state.handle_space() {
2249 wm.dirty = true;
2250 continue;
2251 }
2252 wm.handle_key(0, true, Some('\u{3000}'), false, screen);
2254 wm.dirty = true;
2255 continue;
2256 } else if ev.keycode == 0x01 && ime_state.composing {
2257 ime_state.cancel();
2259 wm.dirty = true;
2260 continue;
2261 } else if ev.keycode == 0x48 && ime_state.converting {
2262 if !ime_state.candidates.is_empty() {
2264 if ime_state.selected_idx > 0 {
2265 ime_state.selected_idx -= 1;
2266 } else {
2267 ime_state.selected_idx = ime_state.candidates.len() - 1;
2268 }
2269 }
2270 wm.dirty = true;
2271 continue;
2272 } else if ev.keycode == 0x50 && ime_state.converting {
2273 if !ime_state.candidates.is_empty() {
2275 ime_state.selected_idx =
2276 (ime_state.selected_idx + 1) % ime_state.candidates.len();
2277 }
2278 wm.dirty = true;
2279 continue;
2280 } else if ime_state.converting {
2281 if let Some(c) = kbd.get_ascii(ev.keycode) {
2283 if ('1'..='9').contains(&c) {
2284 let n = (c as u8 - b'0') as usize;
2285 if let Some(text) = ime_state.select_candidate_by_number(n) {
2286 for ch in text.chars() {
2287 wm.handle_key(0, true, Some(ch), false, screen);
2288 }
2289 wm.dirty = true;
2290 continue;
2291 }
2292 }
2293 }
2294 if let Some(c) = kbd.get_ascii(ev.keycode) {
2296 if c.is_ascii_alphabetic() {
2297 if let Some(text) = ime_state.handle_enter() {
2298 for ch in text.chars() {
2299 wm.handle_key(0, true, Some(ch), false, screen);
2300 }
2301 }
2302 ime_state.input_char(c);
2303 wm.dirty = true;
2304 continue;
2305 }
2306 }
2307 } else if let Some(c) = kbd.get_ascii(ev.keycode) {
2308 if !kbd.ctrl_pressed
2309 && !kbd.alt_pressed
2310 && (c.is_ascii_alphabetic() || c.is_ascii_punctuation())
2311 {
2312 ime_state.input_char(c);
2313 wm.dirty = true;
2314 continue;
2315 }
2316 }
2317 }
2318 }
2319
2320 if ev.pressed {
2321 if !login_mgr.is_unlocked() {
2322 if let Some(c) = kbd.get_ascii(ev.keycode) {
2323 login_mgr.handle_key_input(c);
2324 }
2325 } else if apps::browser::is_active() {
2326 let b = apps::browser::get_instance();
2327 if ev.keycode == 0x01 {
2328 b.engine.active = false;
2331 b.engine.dirty = true;
2332 terminal.dirty = true;
2333
2334 break;
2335 } else if ev.keycode == 0x48 {
2336 b.engine.scroll(-24);
2339 } else if ev.keycode == 0x50 {
2340 b.engine.scroll(24);
2343 } else if ev.keycode == 0x49 {
2344 b.engine.scroll(-240);
2346 } else if ev.keycode == 0x51 {
2347 b.engine.scroll(240);
2349 }
2350 } else {
2351 let mut key_handled = false;
2352 if sysmon_pane.focused {
2353 key_handled = sysmon_pane.handle_key(ev.keycode, kbd.get_ascii(ev.keycode));
2354 }
2355
2356 if !key_handled {
2357 let mut wm = kernel::window_mgr::get_instance();
2358 if wm.handle_key(
2359 ev.keycode,
2360 ev.pressed,
2361 kbd.get_ascii(ev.keycode),
2362 kbd.alt_pressed,
2363 screen,
2364 ) {
2365 continue;
2366 }
2367
2368 if let Some(c) = kbd.get_ascii(ev.keycode) {
2370 if c == '\n' {
2371 if kbd.shift_pressed {
2372 terminal.input_char('\n');
2373 } else {
2374 if let Some(cmd_str) = terminal.submit() {
2375 crate::info!("[SYS] === Executing command: {} ===", cmd_str);
2376 crate::apps::terminal::shell::execute_shell_command(
2377 &cmd_str, terminal, kbd,
2378 );
2379 crate::info!("[SYS] === Command execution finished. ===");
2380 }
2381 break; }
2383 } else if kbd.ctrl_pressed && ev.keycode != 0x0E {
2384 let ctrl_char = match c.to_ascii_lowercase() {
2386 'a' => Some('\x01'),
2387 'b' => Some('\x02'),
2388 'c' => Some('\x03'),
2389 'd' => Some('\x04'),
2390 'e' => Some('\x05'),
2391 'f' => Some('\x06'),
2392 'g' => Some('\x07'),
2393 'h' => Some('\x08'),
2394 'i' => Some('\t'),
2395 'j' => Some('\n'),
2396 'k' => Some('\x0B'),
2397 'l' => Some('\x0C'),
2398 'm' => Some('\r'),
2399 'n' => Some('\x0E'),
2400 'o' => Some('\x0F'),
2401 'p' => Some('\x10'),
2402 'q' => Some('\x11'),
2403 'r' => Some('\x12'),
2404 's' => Some('\x13'),
2405 't' => Some('\x14'),
2406 'u' => Some('\x15'),
2407 'v' => Some('\x16'),
2408 'w' => Some('\x17'),
2409 'x' => Some('\x18'),
2410 'y' => Some('\x19'),
2411 'z' => Some('\x1A'),
2412 _ => None,
2413 };
2414 if let Some(cc) = ctrl_char {
2415 terminal.input_char(cc);
2416 }
2417 } else {
2418 terminal.input_char(c);
2419 }
2420 } else {
2421 if ev.keycode == 0x48 {
2423 terminal.history_up();
2425 } else if ev.keycode == 0x50 {
2426 terminal.history_down();
2428 } else if ev.keycode == 0x4B {
2429 terminal.move_cursor_left();
2431 } else if ev.keycode == 0x4D {
2432 terminal.move_cursor_right();
2434 } else if ev.keycode == 0x53 {
2435 terminal.delete_char();
2437 } else if ev.keycode == 0x47 {
2438 terminal.move_cursor_to_start();
2440 } else if ev.keycode == 0x4F {
2441 terminal.move_cursor_to_end();
2443 } else if ev.keycode == 0x49 {
2444 terminal.scroll(-10);
2446 } else if ev.keycode == 0x51 {
2447 terminal.scroll(10);
2449 } else if ev.keycode == 0x0E {
2450 terminal.input_char('\x08');
2452 } else if ev.keycode == crate::kernel::keyboard::KC_KILL_LINE {
2453 terminal.kill_line();
2455 }
2456 }
2457 }
2458 }
2459 } else {
2460 if login_mgr.is_unlocked() && apps::browser::is_active() {
2463 let b = apps::browser::get_instance();
2464 if !b.address_bar_focused {
2465 b.engine.on_key_up(ev.keycode, kbd.get_ascii(ev.keycode));
2466 }
2467 }
2468 }
2469 }
2470}
2471
2472#[cfg(not(test))]
2473#[panic_handler]
2474fn panic(_info: &PanicInfo) -> ! {
2475 let cid = kernel::scheduler::core_id() as i16;
2480 kernel::allocator::force_release_lock(cid);
2481 kernel::net::force_release_locks(cid);
2482 kernel::usb::force_release_locks(cid);
2483 kernel::fs::force_release_locks(cid);
2484
2485 let is_critical = kernel::scheduler::is_current_process_critical();
2486 let name = kernel::scheduler::get_current_process_name().unwrap_or("unknown");
2487 let pid = kernel::scheduler::get_current_process_id().unwrap_or(0);
2488
2489 if !is_critical {
2490 os_lib::web_engine::fetch_limit::on_process_died(pid);
2502 println!(
2503 "\n=== PROCESS PANIC: Process '{}' (PID: {}) panicked ===",
2504 name, pid
2505 );
2506 println!("{}", _info);
2507 println!("=====================================================");
2508 println!(
2509 "Recovering from process panic: Terminating PID {} and yielding to other processes...",
2510 pid
2511 );
2512 kernel::scheduler::exit();
2513 } else {
2514 println!("\n==================================================");
2515 println!("!!! KERNEL PANIC: CRITICAL PROCESS / KERNEL PANIC !!!");
2516 println!("==================================================");
2517 println!("Critical Process '{}' (PID: {}) failed.", name, pid);
2518 println!("{}", _info);
2519 loop {
2520 unsafe {
2521 core::arch::asm!("wfe");
2522 }
2523 }
2524 }
2525}
2526
2527fn mmu_test_process_a() {
2528 let pt_addr = kernel::scheduler::get_current_page_table().unwrap_or(0);
2529 if pt_addr != 0 {
2530 let phys_mem = alloc::vec![0u8; 16384];
2531 let phys_addr = phys_mem.as_ptr() as u64;
2532 kernel::mmu::map_page(pt_addr, 0x4000_0000, phys_addr);
2533 kernel::scheduler::yield_now();
2534
2535 unsafe {
2536 let ptr = 0x4000_0000 as *mut u64;
2537 ptr.write_volatile(0x1111_1111_1111_1111);
2538 }
2539
2540 println!("Process A wrote 0x1111... to 0x4000_0000. Sleeping...");
2541 kernel::scheduler::sleep(100);
2542
2543 let val = unsafe { (0x4000_0000 as *mut u64).read_volatile() };
2544 println!("Process A read from 0x4000_0000: {:#X}", val);
2545 }
2546 kernel::scheduler::exit();
2547}
2548
2549fn mmu_test_process_b() {
2550 let pt_addr = kernel::scheduler::get_current_page_table().unwrap_or(0);
2551 if pt_addr != 0 {
2552 let phys_mem = alloc::vec![0u8; 16384];
2553 let phys_addr = phys_mem.as_ptr() as u64;
2554 kernel::mmu::map_page(pt_addr, 0x4000_0000, phys_addr);
2555 kernel::scheduler::yield_now();
2556
2557 unsafe {
2558 let ptr = 0x4000_0000 as *mut u64;
2559 ptr.write_volatile(0x2222_2222_2222_2222);
2560 }
2561
2562 println!("Process B wrote 0x2222... to 0x4000_0000. Sleeping...");
2563 kernel::scheduler::sleep(50);
2564
2565 let val = unsafe { (0x4000_0000 as *mut u64).read_volatile() };
2566 println!("Process B read from 0x4000_0000: {:#X}", val);
2567 }
2568 kernel::scheduler::exit();
2569}
2570
2571#[no_mangle]
2575#[link_section = ".user_text"]
2576fn syscall_print(msg: &str) {
2577 let ptr = msg.as_ptr() as usize;
2578 let len = msg.len();
2579 unsafe {
2580 core::arch::asm!(
2581 "svc #0",
2582 in("x8") 2, in("x0") ptr,
2584 in("x1") len,
2585 lateout("x0") _, );
2587 }
2588}
2589
2590#[no_mangle]
2591#[link_section = ".user_text"]
2592fn syscall_yield() {
2593 unsafe {
2594 core::arch::asm!(
2595 "svc #0",
2596 in("x8") 0, lateout("x0") _,
2598 );
2599 }
2600}
2601
2602#[no_mangle]
2603#[link_section = ".user_text"]
2604fn syscall_exit(code: usize) -> ! {
2605 unsafe {
2606 core::arch::asm!(
2607 "svc #0",
2608 in("x8") 1, in("x0") code,
2610 options(noreturn)
2611 );
2612 }
2613}
2614
2615#[no_mangle]
2616#[link_section = ".user_text"]
2617fn user_test_normal() {
2618 syscall_print("Hello from EL0 user space!\n");
2619 syscall_yield();
2620 syscall_print("Back to EL0 user space after yield!\n");
2621 syscall_exit(42);
2622}
2623
2624#[no_mangle]
2627#[link_section = ".user_text"]
2628fn syscall3(nr: usize, x0: usize, x1: usize) -> usize {
2629 let ret: usize;
2630 unsafe {
2631 core::arch::asm!(
2632 "svc #0",
2633 in("x8") nr,
2634 inout("x0") x0 => ret,
2635 in("x1") x1,
2636 );
2637 }
2638 ret
2639}
2640
2641#[no_mangle]
2644#[link_section = ".user_text"]
2645pub fn user_pixel_demo() {
2646 const W: usize = 160;
2647 const H: usize = 120;
2648
2649 let title = "EL0 Pixel Demo";
2651 let req: [usize; 4] = [title.as_ptr() as usize, title.len(), W, H];
2652 let handle = syscall3(5 , req.as_ptr() as usize, 0);
2653 if handle == 0 {
2654 syscall_print("EL0 demo: window create failed\n");
2655 syscall_exit(1);
2656 }
2657
2658 let mut pixels = [0u32; W * H];
2660 let mut tick: u32 = 0;
2661 let mut color_shift: u32 = 0;
2662
2663 loop {
2664 let mut ev: u64 = 0;
2666 while syscall3(
2667 7, handle,
2669 &mut ev as *mut u64 as usize,
2670 ) == 1
2671 {
2672 let kind = ev >> 56;
2673 if kind == 3 {
2674 syscall3(8 , handle, 0);
2676 syscall_print("EL0 demo: window closed, exiting\n");
2677 syscall_exit(0);
2678 }
2679 if kind == 1 && (ev >> 8) & 1 == 1 {
2680 color_shift = color_shift.wrapping_add(64);
2682 }
2683 }
2684
2685 for y in 0..H {
2687 for x in 0..W {
2688 let r = ((x * 255 / W) as u32 + color_shift) & 0xFF;
2689 let g = ((y * 255 / H) as u32) & 0xFF;
2690 let b = (tick * 2) & 0xFF;
2691 pixels[y * W + x] = 0xFF00_0000 | (r << 16) | (g << 8) | b;
2692 }
2693 }
2694 let bar_x = (tick as usize) % W;
2695 for y in 0..H {
2696 pixels[y * W + bar_x] = 0xFFFFFFFF;
2697 }
2698
2699 syscall3(6 , handle, pixels.as_ptr() as usize);
2701
2702 tick = tick.wrapping_add(1);
2703 for _ in 0..3 {
2705 syscall_yield();
2706 }
2707 }
2708}
2709
2710#[no_mangle]
2711#[link_section = ".user_text"]
2712fn user_test_abort() {
2713 syscall_print("Starting abort test process in EL0...\n");
2714
2715 let mmio_ptr = 0x3F20_0008 as *mut u32;
2719 unsafe {
2720 core::ptr::write_volatile(mmio_ptr, 0);
2721 }
2722
2723 syscall_print("ERROR: Accessed MMIO without abort!\n");
2725 syscall_exit(99);
2726}