Start a new kernel thread by adding it to the process table. This won't run immediately, but will run when the scheduler next switches to it. Inputs ------ function : fn() -> () The new thread entry point Returns ------- The TID of the new thread Note: returning Box to be scheduled leads to panic in VirtAddr::new(). Cause unknown, exposing memory/stack bug?
(
function: fn()->(),
mut handles: Vec<Arc<RwLock<Rendezvous>>>
)
| 360 | /// exposing memory/stack bug? |
| 361 | /// |
| 362 | pub fn new_kernel_thread( |
| 363 | function: fn()->(), |
| 364 | mut handles: Vec<Arc<RwLock<Rendezvous>>> |
| 365 | ) -> u64 { |
| 366 | |
| 367 | // Create a new process table entry |
| 368 | // |
| 369 | // Note this is first created on the stack, then moved into a Box |
| 370 | // on the heap. |
| 371 | let new_thread = { |
| 372 | // Allocate both "user" and kernel stacks in kernel memory |
| 373 | let kernel_stack = Vec::with_capacity(KERNEL_STACK_SIZE + USER_STACK_SIZE); |
| 374 | let kernel_stack_start = VirtAddr::from_ptr(kernel_stack.as_ptr()); |
| 375 | let kernel_stack_end = (kernel_stack_start + KERNEL_STACK_SIZE).as_u64(); |
| 376 | let user_stack_end = kernel_stack_end + (USER_STACK_SIZE as u64); |
| 377 | |
| 378 | Box::new(Thread { |
| 379 | tid: unique_id(), |
| 380 | process: Arc::new(RwLock::new(Process { |
| 381 | page_table_physaddr: 0, |
| 382 | // Wrap each handle in an Option |
| 383 | handles:handles.drain(..) |
| 384 | .map(|h| Some(h)).collect(), |
| 385 | // Empty set of mount paths |
| 386 | mounts: vfs::VFS::new() |
| 387 | })), |
| 388 | page_table_physaddr: 0, // Don't need to switch PT |
| 389 | kernel_stack, |
| 390 | // Note that stacks move backwards, so SP points to the end |
| 391 | kernel_stack_end, |
| 392 | user_stack_end, |
| 393 | // Push a Context struct on the kernel stack |
| 394 | context: kernel_stack_end - INTERRUPT_CONTEXT_SIZE as u64, |
| 395 | }) |
| 396 | }; |
| 397 | |
| 398 | // Cast context address to Context struct |
| 399 | let context = new_thread.context_mut(); |
| 400 | |
| 401 | // Set the instruction pointer |
| 402 | context.rip = function as usize; |
| 403 | |
| 404 | // Set flags |
| 405 | context.rflags = 0x200; |
| 406 | |
| 407 | // Set segment selector flags |
| 408 | let (code_selector, data_selector) = gdt::get_kernel_segments(); |
| 409 | context.cs = code_selector.0 as usize; |
| 410 | context.ss = data_selector.0 as usize; |
| 411 | |
| 412 | // The kernel thread has its own stack |
| 413 | // Note: Need to point to the end of the memory region |
| 414 | // because the stack moves down in memory |
| 415 | context.rsp = new_thread.user_stack_end as usize; |
| 416 | |
| 417 | let tid = new_thread.tid; |
| 418 | schedule_thread(new_thread); |
| 419 | tid |
no test coverage detected