/ kernel / core / process.c
process.c
  1  #include "process.h"
  2  #include "memory.h"
  3  #include "kernel.h"
  4  #include "string.h"
  5  #include "idt.h"
  6  #include "fs.h"
  7  #include "elf.h"
  8  #include "fd.h"
  9  #include "paging.h"
 10  
 11  // Stack sizes
 12  #define KERNEL_STACK_SIZE 4096  // 4KB kernel stack per process
 13  #define USER_STACK_SIZE   8192  // 8KB user stack
 14  
 15  struct process* process_list = 0;
 16  struct process* current_process = 0;
 17  static uint32_t next_pid = 1;
 18  
 19  #define USER_STACK_TOP  0xC0000000  // User stack top
 20  
 21  void process_init(void) {
 22      // Create kernel process
 23      struct process* kernel_proc = (struct process*)kmalloc(sizeof(struct process));
 24      memset(kernel_proc, 0, sizeof(struct process));
 25      
 26      kernel_proc->pid = 0;
 27      kernel_proc->state = PROCESS_RUNNING;
 28      kernel_proc->next = 0;
 29      
 30      process_list = kernel_proc;
 31      current_process = kernel_proc;
 32      
 33      terminal_writestring("Process management initialized\n");
 34  }
 35  
 36  struct process* process_create(void* entry_point) {
 37      struct process* proc = (struct process*)kmalloc(sizeof(struct process));
 38      memset(proc, 0, sizeof(struct process));
 39      
 40      // Initialize process structure
 41      proc->pid = next_pid++;
 42      proc->eip = (uint32_t)entry_point;
 43      proc->state = PROCESS_READY;
 44      proc->blocked_on_ring_fd = -1;
 45      proc->min_complete = 0;
 46      proc->page_directory = 0;  // No separate page directory initially
 47      
 48      // Initialize file descriptors to NULL
 49      for (int i = 0; i < 32; i++) {
 50          proc->fds[i] = NULL;
 51      }
 52      
 53      // Allocate user stack
 54      proc->stack_end = USER_STACK_TOP - USER_STACK_SIZE;
 55      proc->stack_start = USER_STACK_TOP;
 56      
 57      // Actually allocate memory for the stack
 58      uint32_t stack_phys = (uint32_t)kmalloc_aligned(USER_STACK_SIZE);
 59      terminal_writestring("Allocated stack at 0x");
 60      char sbuf[9];
 61      itoa(stack_phys, sbuf, 16);
 62      terminal_writestring(sbuf);
 63      terminal_writestring("\n");
 64      
 65      proc->esp = proc->stack_start - 4;  // Leave room for return address
 66      proc->ebp = proc->esp;
 67      
 68      // Allocate kernel stack
 69      proc->kernel_stack = (uint32_t)kmalloc_aligned(KERNEL_STACK_SIZE);  // 4KB kernel stack
 70      
 71      // Add to process list
 72      proc->next = process_list;
 73      process_list = proc;
 74      
 75      // Initialize standard I/O for the process
 76      struct process* old_current = current_process;
 77      current_process = proc;
 78      fd_init_stdio();
 79      current_process = old_current;
 80      
 81      terminal_writestring("Created process PID ");
 82      char buf[12];
 83      itoa(proc->pid, buf, 10);
 84      terminal_writestring(buf);
 85      terminal_writestring("\n");
 86      
 87      return proc;
 88  }
 89  
 90  int process_fork(void) {
 91      if (!current_process) return -1;
 92  
 93      // Clone page directory
 94      page_directory_t* new_dir = clone_directory(current_directory);
 95      if (!new_dir) return -1;
 96  
 97      // Allocate new process struct
 98      struct process* child = (struct process*)kmalloc(sizeof(struct process));
 99      memcpy(child, current_process, sizeof(struct process));
100  
101      child->pid = next_pid++;
102      child->state = PROCESS_READY;
103  
104      // Allocate new kernel stack
105      child->kernel_stack = (uint32_t)kmalloc_aligned(KERNEL_STACK_SIZE);
106  
107      // Set new page directory
108      child->page_directory = (uint32_t)new_dir;
109  
110      // Add child to process list (head insertion)
111      child->next = process_list;
112      process_list = child;
113  
114      terminal_writestring("Forked process PID ");
115      char buf[12];
116      itoa(child->pid, buf, 10);
117      terminal_writestring(buf);
118      terminal_writestring("\n");
119  
120      // Return child's pid to parent
121      return child->pid;
122  }
123  
124  void process_switch(struct process* proc) {
125      if (!proc || proc == current_process) {
126          return;
127      }
128      
129      // Save current process state (TODO)
130      
131      current_process = proc;
132      proc->state = PROCESS_RUNNING;
133  
134      // Switch to process page directory if present
135      if (proc->page_directory) {
136          switch_page_directory((page_directory_t*)proc->page_directory);
137      }
138  
139      terminal_writestring("Switching to process PID ");
140      char buf[12];
141      itoa(proc->pid, buf, 10);
142      terminal_writestring(buf);
143      terminal_writestring("\n");
144      
145      extern void jump_to_userspace(uint32_t entry, uint32_t stack);
146      uint32_t user_stack = proc->stack_start - 4;
147      jump_to_userspace(proc->eip, user_stack);
148      terminal_writestring("ERROR: Returned from userspace?!\n");
149  }
150  
151  void process_exit(int status) {
152      (void)status;
153      
154      if (current_process) {
155          current_process->state = PROCESS_ZOMBIE;
156          terminal_writestring("Process ");
157          char buf[12];
158          itoa(current_process->pid, buf, 10);
159          terminal_writestring(buf);
160          terminal_writestring(" exited\n");
161      }
162      
163      // Switch to next ready process or halt
164      struct process* next = process_list;
165      while (next) {
166          if (next->state == PROCESS_READY && next != current_process) {
167              process_switch(next);
168              return;
169          }
170          next = next->next;
171      }
172      
173      // No more processes
174      terminal_writestring("No more processes to run\n");
175      while (1) { hlt(); }
176  }
177  
178  struct process* process_get_current(void) {
179      return current_process;
180  }
181  
182  int process_exec(const char* filename) {
183      // Find file in filesystem
184      struct fs_node* file = fs_finddir(fs_root, (char*)filename);
185      if (!file) {
186          terminal_writestring("File not found: ");
187          terminal_writestring(filename);
188          terminal_writestring("\n");
189          return -1;
190      }
191      
192      // Read file into memory
193      uint8_t* buffer = (uint8_t*)kmalloc(file->length);
194      uint32_t size = fs_read(file, 0, file->length, buffer);
195      if (size != file->length) {
196          kfree(buffer);
197          terminal_writestring("Failed to read file\n");
198          return -1;
199      }
200      
201      // Load ELF file
202      void* entry = elf_load_file(buffer);
203      kfree(buffer);
204      
205      if (!entry) {
206          terminal_writestring("Failed to load ELF\n");
207          return -1;
208      }
209      
210      // Create process
211      struct process* proc = process_create(entry);
212      
213      // Switch to it
214      process_switch(proc);
215      
216      return 0;
217  }
218  
219  // Block current process on io_uring
220  void process_block(int ring_fd, uint32_t min_complete) {
221      if (!current_process) return;
222      
223      current_process->state = PROCESS_BLOCKED;
224      current_process->blocked_on_ring_fd = ring_fd;
225      current_process->min_complete = min_complete;
226      
227      // Switch to next ready process
228      process_yield();
229  }
230  
231  // Unblock a process
232  void process_unblock(struct process* proc) {
233      if (!proc) return;
234      
235      proc->state = PROCESS_READY;
236      proc->blocked_on_ring_fd = -1;
237      proc->min_complete = 0;
238  }
239  
240  // Yield CPU to next ready process
241  void process_yield(void) {
242      if (!current_process || !process_list) return;
243      
244      // Count valid userspace processes
245      int valid_process_count = 0;
246      struct process* temp = process_list;
247      while (temp) {
248          if (temp->eip != 0 && temp->pid != 0 && 
249              (temp->state == PROCESS_READY || temp->state == PROCESS_RUNNING)) {
250              valid_process_count++;
251          }
252          temp = temp->next;
253      }
254      
255      // If only one valid process, don't switch
256      if (valid_process_count <= 1) {
257          return;
258      }
259      
260      // Find next ready process
261      struct process* next = current_process->next;
262      if (!next) next = process_list;
263      
264      struct process* start = next;
265      while (next->state != PROCESS_READY && next->state != PROCESS_RUNNING) {
266          next = next->next;
267          if (!next) next = process_list;
268          
269          // If we've checked all processes and none are ready, halt
270          if (next == start) {
271              terminal_writestring("No ready processes! Halting.\n");
272              __asm__ volatile("hlt");
273              return;
274          }
275      }
276      
277      // Skip processes with invalid entry points (like kernel process at 0x0)
278      while (next->eip == 0 || next->pid == 0) {
279          next = next->next;
280          if (!next) next = process_list;
281          
282          // If we've looped back to start, no valid processes
283          if (next == start) {
284              terminal_writestring("No valid processes! Halting.\n");
285              __asm__ volatile("hlt");
286              return;
287          }
288      }
289      
290      // Switch to the next ready process
291      if (next != current_process) {
292          process_switch(next);
293      }
294  }