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 }