use crate::{
build_flags, fs::Fd, map_portal, parse_flags, processor::ProcessorInner, Sv39, Sv39Manager,
PROCESSOR,
};
use alloc::{alloc::alloc_zeroed, boxed::Box, sync::Arc, vec::Vec};
use core::alloc::Layout;
use spin::Mutex;
use tg_kernel_context::{foreign::ForeignContext, LocalContext};
use tg_kernel_vm::{
page_table::{MmuMeta, VAddr, PPN, VPN},
AddressSpace,
};
use tg_signal::Signal;
use tg_signal_impl::SignalImpl;
use tg_sync::{Condvar, Mutex as MutexTrait, Semaphore};
use tg_task_manage::{ProcId, ThreadId};
use xmas_elf::{
header::{self, HeaderPt2, Machine},
program, ElfFile,
};
pub struct Thread {
pub tid: ThreadId,
pub context: ForeignContext,
}
impl Thread {
pub fn new(satp: usize, context: LocalContext) -> Self {
Self {
tid: ThreadId::new(),
context: ForeignContext { context, satp },
}
}
}
pub struct Process {
pub pid: ProcId,
pub address_space: AddressSpace<Sv39, Sv39Manager>,
pub fd_table: Vec<Option<Mutex<Fd>>>,
pub signal: Box<dyn Signal>,
pub semaphore_list: Vec<Option<Arc<Semaphore>>>,
pub mutex_list: Vec<Option<Arc<dyn MutexTrait>>>,
pub condvar_list: Vec<Option<Arc<Condvar>>>,
}
impl Process {
pub fn exec(&mut self, elf: ElfFile) {
let (proc, thread) = Process::from_elf(elf).unwrap();
self.address_space = proc.address_space;
let processor: *mut ProcessorInner = PROCESSOR.get_mut() as *mut ProcessorInner;
unsafe {
let pthreads = (*processor).get_thread(self.pid).unwrap();
(*processor).get_task(pthreads[0]).unwrap().context = thread.context;
}
}
pub fn fork(&mut self) -> Option<(Self, Thread)> {
let pid = ProcId::new();
let parent_addr_space = &self.address_space;
let mut address_space: AddressSpace<Sv39, Sv39Manager> = AddressSpace::new();
parent_addr_space.cloneself(&mut address_space);
map_portal(&address_space);
let processor: *mut ProcessorInner = PROCESSOR.get_mut() as *mut ProcessorInner;
let pthreads = unsafe { (*processor).get_thread(self.pid).unwrap() };
let context = unsafe {
(*processor).get_task(pthreads[0]).unwrap().context.context.clone()
};
let satp = (8 << 60) | address_space.root_ppn().val();
let thread = Thread::new(satp, context);
let new_fd_table: Vec<Option<Mutex<Fd>>> = self.fd_table
.iter()
.map(|fd| fd.as_ref().map(|f| Mutex::new(f.lock().clone())))
.collect();
Some((
Self {
pid,
address_space,
fd_table: new_fd_table,
signal: self.signal.from_fork(),
semaphore_list: Vec::new(),
mutex_list: Vec::new(),
condvar_list: Vec::new(),
},
thread,
))
}
pub fn from_elf(elf: ElfFile) -> Option<(Self, Thread)> {
let entry = match elf.header.pt2 {
HeaderPt2::Header64(pt2)
if pt2.type_.as_type() == header::Type::Executable
&& pt2.machine.as_machine() == Machine::RISC_V =>
{ pt2.entry_point as usize }
_ => None?,
};
const PAGE_SIZE: usize = 1 << Sv39::PAGE_BITS;
const PAGE_MASK: usize = PAGE_SIZE - 1;
let mut address_space = AddressSpace::new();
for program in elf.program_iter() {
if !matches!(program.get_type(), Ok(program::Type::Load)) { continue; }
let off_file = program.offset() as usize;
let len_file = program.file_size() as usize;
let off_mem = program.virtual_addr() as usize;
let end_mem = off_mem + program.mem_size() as usize;
assert_eq!(off_file & PAGE_MASK, off_mem & PAGE_MASK);
let mut flags: [u8; 5] = *b"U___V";
if program.flags().is_execute() { flags[1] = b'X'; }
if program.flags().is_write() { flags[2] = b'W'; }
if program.flags().is_read() { flags[3] = b'R'; }
address_space.map(
VAddr::new(off_mem).floor()..VAddr::new(end_mem).ceil(),
&elf.input[off_file..][..len_file],
off_mem & PAGE_MASK,
parse_flags(unsafe { core::str::from_utf8_unchecked(&flags) }).unwrap(),
);
}
let stack = unsafe {
alloc_zeroed(Layout::from_size_align_unchecked(
2 << Sv39::PAGE_BITS, 1 << Sv39::PAGE_BITS,
))
};
address_space.map_extern(
VPN::new((1 << 26) - 2)..VPN::new(1 << 26),
PPN::new(stack as usize >> Sv39::PAGE_BITS),
build_flags("U_WRV"),
);
map_portal(&address_space);
let satp = (8 << 60) | address_space.root_ppn().val();
let mut context = LocalContext::user(entry);
*context.sp_mut() = 1 << 38;
let thread = Thread::new(satp, context);
Some((
Self {
pid: ProcId::new(),
address_space,
fd_table: vec![
Some(Mutex::new(Fd::Empty { read: true, write: false })),
Some(Mutex::new(Fd::Empty { read: false, write: true })),
Some(Mutex::new(Fd::Empty { read: false, write: true })),
],
signal: Box::new(SignalImpl::new()),
semaphore_list: Vec::new(),
mutex_list: Vec::new(),
condvar_list: Vec::new(),
},
thread,
))
}
}