1
+ use alloc:: collections:: VecDeque ;
2
+ use core:: arch:: { asm, global_asm} ;
3
+ use crate :: dos:: cooperative_multitasking:: task:: { Registers , Task } ;
4
+
5
+ mod task;
6
+
7
+ global_asm ! ( include_str!( "cooperative_task_switching.S" ) ) ;
8
+
9
+ extern "C" {
10
+ fn cooperative_task_switching_assembly ( from : * mut Registers , to : * mut Registers ) -> ( ) ;
11
+ }
12
+
13
+ pub struct Tasking {
14
+ task_list : Option < VecDeque < Task > > ,
15
+ current_task_id : u8 ,
16
+ eflags_register : u32 ,
17
+ cr3_register : u32 ,
18
+ initialized : bool ,
19
+ }
20
+
21
+ impl Tasking {
22
+ const MAX_TASKS : usize = 10 ;
23
+
24
+ pub fn init ( & mut self ) {
25
+ if self . task_list . is_some ( ) {
26
+ self . task_list = None ;
27
+ }
28
+ let ( eflags, cr3) = Self :: get_eflags_and_cr3_registers ( ) ;
29
+
30
+ // Create main task
31
+ self . task_list = Some ( VecDeque :: with_capacity ( Self :: MAX_TASKS ) ) ;
32
+ self . current_task_id = 0 ;
33
+ self . eflags_register = eflags;
34
+ self . cr3_register = cr3;
35
+ self . initialized = true ;
36
+ self . task_list . as_mut ( ) . unwrap ( ) . push_back ( Task {
37
+ registers : Registers {
38
+ eax : 0 ,
39
+ ebx : 0 ,
40
+ ecx : 0 ,
41
+ edx : 0 ,
42
+ esi : 0 ,
43
+ edi : 0 ,
44
+ esp : 0 ,
45
+ ebp : 0 ,
46
+ eip : 0 ,
47
+ eflags,
48
+ cr3,
49
+ } ,
50
+ } ) ;
51
+ }
52
+
53
+ pub fn add_task ( & mut self , main_function : * mut fn ( ) ) -> Result < ( ) , & ' static str > {
54
+ if !self . initialized {
55
+ return Err ( "Cooperative tasking manager is not initialized" ) ;
56
+ }
57
+ if self . task_list . as_ref ( ) . unwrap ( ) . len ( ) >= Self :: MAX_TASKS {
58
+ return Err ( "Maximum number of tasks reached" ) ;
59
+ }
60
+ let task_list = self . task_list . as_mut ( ) . unwrap ( ) ;
61
+ task_list. push_back ( Task :: new ( main_function, self . eflags_register , self . cr3_register as * mut u32 , task_list. len ( ) as u8 ) ) ;
62
+ Ok ( ( ) )
63
+ }
64
+
65
+ pub fn yield_task ( & mut self ) {
66
+ if !self . initialized {
67
+ panic ! ( "Cooperative tasking manager is not initialized" ) ;
68
+ }
69
+
70
+ let task_list = self . task_list . as_mut ( ) . unwrap ( ) ;
71
+
72
+ let current_task_registers_ptr = & mut task_list[ self . current_task_id as usize ] . registers as * mut Registers ;
73
+
74
+ self . current_task_id += 1 ;
75
+ if self . current_task_id >= task_list. len ( ) as u8 {
76
+ self . current_task_id = 0 ;
77
+ }
78
+
79
+ let next_task_registers_ptr = & mut task_list[ self . current_task_id as usize ] . registers as * mut Registers ;
80
+
81
+ unsafe {
82
+ cooperative_task_switching_assembly ( current_task_registers_ptr, next_task_registers_ptr) ;
83
+ }
84
+ }
85
+
86
+ fn get_eflags_and_cr3_registers ( ) -> ( u32 , u32 ) {
87
+ let mut eflags: u32 ;
88
+ let mut cr3: u32 ;
89
+ unsafe {
90
+ // Read CR3
91
+ asm ! ( "mov {}, cr3" , out( reg) cr3) ;
92
+ // Read EFLAGS
93
+ asm ! ( "pushfd; mov eax, [esp]; mov {}, eax; popfd;" , out( reg) eflags) ;
94
+ }
95
+ ( eflags, cr3)
96
+ }
97
+ }
98
+
99
+ pub static mut TASKING : Tasking = Tasking {
100
+ task_list : None ,
101
+ current_task_id : 0 ,
102
+ eflags_register : 0 ,
103
+ cr3_register : 0 ,
104
+ initialized : false ,
105
+ } ;
106
+
107
+ #[ macro_export]
108
+ macro_rules! yield_cooperative_task {
109
+ ( ) => {
110
+ unsafe {
111
+ $crate:: dos:: cooperative_multitasking:: TASKING . yield_task( ) ;
112
+ }
113
+ } ;
114
+ }
115
+
116
+ #[ macro_export]
117
+ macro_rules! add_cooperative_task {
118
+ ( $main_function: expr) => {
119
+ unsafe {
120
+ $crate:: dos:: cooperative_multitasking:: TASKING . add_task( $main_function as * mut fn ( ) )
121
+ }
122
+ } ;
123
+ }
0 commit comments