⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/
test_tasks.rs

1//! Test tasks for verifying context switching functionality
2//!
3//! These tasks are designed to test that context switching works properly
4//! on all architectures, with special handling for AArch64's loop limitations.
5//!
6//! # Safety note (AArch64 UART calls)
7//!
8//! All `unsafe { uart_write_str(...) }` blocks in this file perform MMIO
9//! writes to the QEMU virt machine UART at 0x0900_0000.  This address is
10//! mapped and valid throughout kernel execution on this platform.  The
11//! function only writes bytes to the UART data register and cannot cause
12//! memory corruption.
13
14#![allow(clippy::fn_to_numeric_cast, function_casts_as_integer)]
15
16use crate::sched;
17
18/// Test task A - prints messages and yields
19#[no_mangle]
20pub extern "C" fn test_task_a() -> ! {
21    #[cfg(target_arch = "aarch64")]
22    {
23        use crate::arch::aarch64::direct_uart::{direct_print_num, uart_write_str};
24
25        // SAFETY: The entire block is unsafe because:
26        // 1. uart_write_str performs MMIO writes to the QEMU virt UART (see
27        //    module-level safety note).
28        // 2. Inline asm! instructions implement a busy-wait delay loop using scratch
29        //    registers x0-x2.  These registers are caller-saved (volatile) in the
30        //    AArch64 calling convention and are not live across the asm blocks.  The
31        //    instructions (mov, sub, cbnz) have no side effects beyond register
32        //    modification and cannot fault.
33        unsafe {
34            let mut counter = 0u64;
35
36            uart_write_str("[TASK A] Started\n");
37
38            loop {
39                // Print message
40                uart_write_str("[TASK A] Running - count: ");
41                direct_print_num(counter);
42                uart_write_str("\n");
43
44                // Yield to other tasks
45                sched::yield_cpu();
46
47                // Increment counter
48                counter = counter.wrapping_add(1);
49
50                // Manual delay using assembly
51                core::arch::asm!("mov x0, #50000");
52                core::arch::asm!("mov x1, #10");
53                core::arch::asm!("2: mov x2, x0");
54                core::arch::asm!("1: sub x2, x2, #1");
55                core::arch::asm!("cbnz x2, 1b");
56                core::arch::asm!("sub x1, x1, #1");
57                core::arch::asm!("cbnz x1, 2b");
58            }
59        }
60    }
61
62    #[cfg(not(target_arch = "aarch64"))]
63    {
64        let mut counter = 0u64;
65
66        println!("[TASK A] Started");
67
68        loop {
69            println!("[TASK A] Running - count: {}", counter);
70
71            // Yield to other tasks
72            sched::yield_cpu();
73
74            counter = counter.wrapping_add(1);
75
76            // Delay
77            for _ in 0..500000 {
78                core::hint::spin_loop();
79            }
80        }
81    }
82}
83
84/// Test task B - prints different messages and yields
85#[no_mangle]
86pub extern "C" fn test_task_b() -> ! {
87    #[cfg(target_arch = "aarch64")]
88    {
89        use crate::arch::aarch64::direct_uart::{direct_print_num, uart_write_str};
90
91        // SAFETY: Same rationale as test_task_a -- MMIO UART writes and
92        // scratch-register-only delay loop.  See module-level safety note
93        // for UART details and test_task_a for asm! rationale.
94        unsafe {
95            let mut counter = 0u64;
96
97            uart_write_str("[TASK B] Started\n");
98
99            loop {
100                // Print message
101                uart_write_str("[TASK B] Executing - value: ");
102                direct_print_num(counter);
103                uart_write_str("\n");
104
105                // Yield to other tasks
106                sched::yield_cpu();
107
108                // Increment counter by 10
109                counter = counter.wrapping_add(10);
110
111                // Manual delay using assembly
112                core::arch::asm!("mov x0, #50000");
113                core::arch::asm!("mov x1, #15");
114                core::arch::asm!("2: mov x2, x0");
115                core::arch::asm!("1: sub x2, x2, #1");
116                core::arch::asm!("cbnz x2, 1b");
117                core::arch::asm!("sub x1, x1, #1");
118                core::arch::asm!("cbnz x1, 2b");
119            }
120        }
121    }
122
123    #[cfg(not(target_arch = "aarch64"))]
124    {
125        let mut counter = 0u64;
126
127        println!("[TASK B] Started");
128
129        loop {
130            println!("[TASK B] Executing - value: 0x{:x}", counter);
131
132            // Yield to other tasks
133            sched::yield_cpu();
134
135            counter = counter.wrapping_add(10);
136
137            // Delay
138            for _ in 0..750000 {
139                core::hint::spin_loop();
140            }
141        }
142    }
143}
144
145/// Create test tasks for context switching verification
146pub fn create_test_tasks() {
147    #[cfg(feature = "alloc")]
148    {
149        use alloc::string::String;
150
151        use crate::process;
152
153        kprintln!("[TEST] Creating test tasks for context switch verification");
154
155        // Create Task A
156        match process::lifecycle::create_process(String::from("test_task_a"), 0) {
157            Ok(_pid_a) => {
158                kprintln!("[TEST] Created process A");
159
160                if let Err(_e) = process::create_thread(test_task_a as usize, 0, 0, 0) {
161                    kprintln!("[TEST] Failed to create thread for task A");
162                } else {
163                    kprintln!("[TEST] Created thread for task A");
164                }
165            }
166            Err(_e) => {
167                kprintln!("[TEST] Failed to create task A");
168            }
169        }
170
171        // Create Task B
172        match process::lifecycle::create_process(String::from("test_task_b"), 0) {
173            Ok(_pid_b) => {
174                kprintln!("[TEST] Created process B");
175
176                if let Err(_e) = process::create_thread(test_task_b as usize, 0, 0, 0) {
177                    kprintln!("[TEST] Failed to create thread for task B");
178                } else {
179                    kprintln!("[TEST] Created thread for task B");
180                }
181            }
182            Err(_e) => {
183                kprintln!("[TEST] Failed to create task B");
184            }
185        }
186
187        kprintln!("[TEST] Test tasks created successfully");
188    }
189
190    #[cfg(not(feature = "alloc"))]
191    {
192        kprintln!("[TEST] Cannot create test tasks: alloc feature not enabled");
193    }
194}