diff --git a/Cargo.lock b/Cargo.lock index 2e55891..ca1027a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,7 +189,7 @@ dependencies = [ [[package]] name = "ggos_kernel" -version = "0.7.0" +version = "0.7.2" dependencies = [ "bit_field", "bitflags", diff --git a/Makefile b/Makefile index 32b7035..4d51ec3 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ ifeq (${RUN_MODE}, nographic) QEMU_ARGS = -nographic endif -.PHONY: build run debug clean launch \ +.PHONY: build run debug clean launch intdbg \ target/x86_64-unknown-uefi/$(MODE)/ggos_boot.efi \ target/x86_64-unknown-none/$(MODE)/ggos_kernel \ target/x86_64-unknown-ggos/$(MODE) @@ -32,6 +32,13 @@ launch: $(QEMU_ARGS) \ -drive format=raw,file=fat:rw:${ESP} +intdbg: + @qemu-system-x86_64 \ + -bios ${OVMF} \ + -net none \ + $(QEMU_ARGS) \ + -drive format=raw,file=fat:rw:${ESP} -no-reboot -d int,cpu_reset + debug: build @qemu-system-x86_64 \ -bios ${OVMF} \ diff --git a/pkg/app/hello/src/main.rs b/pkg/app/hello/src/main.rs index 379f3e3..8278496 100644 --- a/pkg/app/hello/src/main.rs +++ b/pkg/app/hello/src/main.rs @@ -9,7 +9,8 @@ fn main() { println!("Hello, world!!!"); let time = lib::sys_time(); println!("Now at: {}", time); - lib::sys_exit(0); + println!("Exiting..."); + lib::sys_exit(233); } entry!(main); diff --git a/pkg/app/sh/src/main.rs b/pkg/app/sh/src/main.rs index d5fd269..b1dd360 100644 --- a/pkg/app/sh/src/main.rs +++ b/pkg/app/sh/src/main.rs @@ -12,8 +12,6 @@ extern crate lib; fn main() { - sys_list_dir("/"); - let mut root_dir = String::from("/APP/"); loop { @@ -28,6 +26,9 @@ fn main() { // ggos::filesystem::cat(root_dir.as_str(), line[1]); } "cd" => { + if line[1].starts_with("/") { + root_dir = String::from(line[1]); + } match line[1] { ".." => { if root_dir.as_str() == "/" { @@ -37,6 +38,7 @@ fn main() { let pos = root_dir.rfind('/').unwrap(); root_dir = root_dir[..pos + 1].to_string(); }, + "." => break, _ => { root_dir.push_str(line[1]); root_dir.push('/'); @@ -46,15 +48,22 @@ fn main() { } "exec" => { let path = root_dir.clone() + line[1]; - println!("ready to exec {}...", path); + let start = sys_time(); + let pid = sys_spawn(path.as_str()); if pid == 0 { - println!("failed to spawn process: {}#{}", line[1], pid); + println!("[!] failed to spawn process: {}#{}", line[1], pid); + continue; } else { - println!("spawned process: {}#{}", line[1], pid); + println!("[+] spawned process: {}#{}", line[1], pid); } + + let ret = sys_wait_pid(pid); + let time = sys_time() - start ; + + println!("[+] process exited with code {} @ {}s", ret, time.num_seconds()); } - _ => println!("[=] {}", input), + _ => println!("[=] you said \"{}\"", input), } } diff --git a/pkg/elf/src/lib.rs b/pkg/elf/src/lib.rs index 7e6a22d..fff74f3 100644 --- a/pkg/elf/src/lib.rs +++ b/pkg/elf/src/lib.rs @@ -16,7 +16,7 @@ pub fn map_physical_memory( page_table: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) { - debug!("Mapping physical memory..."); + trace!("Mapping physical memory..."); let start_frame = PhysFrame::containing_address(PhysAddr::new(0)); let end_frame = PhysFrame::containing_address(PhysAddr::new(max_addr)); @@ -40,7 +40,7 @@ pub fn map_elf( page_table: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) -> Result<(), MapToError> { - debug!("Mapping ELF file...{:?}", elf.input.as_ptr()); + trace!("Mapping ELF file...{:?}", elf.input.as_ptr()); let start = PhysAddr::new(elf.input.as_ptr() as u64); for segment in elf.program_iter() { map_segment(&segment, start, page_table, frame_allocator)?; @@ -50,7 +50,7 @@ pub fn map_elf( /// Unmap ELF file pub fn unmap_elf(elf: &ElfFile, page_table: &mut impl Mapper) -> Result<(), UnmapError> { - debug!("Unmapping ELF file..."); + trace!("Unmapping ELF file..."); let kernel_start = PhysAddr::new(elf.input.as_ptr() as u64); for segment in elf.program_iter() { unmap_segment(&segment, kernel_start, page_table)?; @@ -65,7 +65,7 @@ pub fn map_stack( page_table: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) -> Result<(), MapToError> { - debug!("mapping stack at {:#x}", addr); + trace!("mapping stack at {:#x}", addr); // create a stack let stack_start = Page::containing_address(VirtAddr::new(addr)); let stack_end = stack_start + pages; @@ -96,7 +96,7 @@ fn map_segment( return Ok(()); } - debug!("Mapping segment: {:#x?}", segment); + trace!("Mapping segment: {:#x?}", segment); let mem_size = segment.mem_size(); let file_size = segment.file_size(); let file_offset = segment.offset() & !0xfff; @@ -201,7 +201,7 @@ fn unmap_segment( if segment.get_type().unwrap() != program::Type::Load { return Ok(()); } - debug!("Unmapping segment: {:#x?}", segment); + trace!("Unmapping segment: {:#x?}", segment); let mem_size = segment.mem_size(); let file_size = segment.file_size(); let file_offset = segment.offset() & !0xfff; diff --git a/pkg/fs/src/device/disk.rs b/pkg/fs/src/device/disk.rs index a9fa95a..ee22ab6 100644 --- a/pkg/fs/src/device/disk.rs +++ b/pkg/fs/src/device/disk.rs @@ -181,7 +181,7 @@ where where F: FnMut(&DirEntry), { - debug!("Iterating directory: {:?}", dir); + trace!("Iterating directory: {:?}", dir); let mut current_cluster = Some(dir.cluster); let mut dir_sector_num = self.cluster_to_sector(&dir.cluster); let dir_size = match dir.cluster { @@ -201,7 +201,7 @@ where if dir_entry.is_eod() { return Ok(()); } else if dir_entry.is_valid() && !dir_entry.is_long_name() { - debug!("found file {}", dir_entry.filename()); + trace!("found file {}", dir_entry.filename()); func(&dir_entry); } } diff --git a/pkg/kernel/Cargo.toml b/pkg/kernel/Cargo.toml index 6b09bf2..3a0b74b 100644 --- a/pkg/kernel/Cargo.toml +++ b/pkg/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ggos_kernel" -version = "0.7.0" +version = "0.7.2" edition = "2021" authors = ["GZTime "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/pkg/kernel/src/interrupt/handlers.rs b/pkg/kernel/src/interrupt/handlers.rs index e19a420..fa5de69 100644 --- a/pkg/kernel/src/interrupt/handlers.rs +++ b/pkg/kernel/src/interrupt/handlers.rs @@ -32,11 +32,11 @@ pub unsafe fn reg_idt(idt: &mut InterruptDescriptorTable) { idt[(consts::Interrupts::IRQ0 as u8 + consts::IRQ::Timer as u8) as usize] .set_handler_fn(clock_handler) - .set_stack_index(crate::gdt::CONTEXT_SWITCH); + .set_stack_index(crate::gdt::CONTEXT_SWITCH_IST_INDEX); idt[consts::Interrupts::Syscall as usize] .set_handler_fn(syscall_handler) - .set_stack_index(crate::gdt::CONTEXT_SWITCH) + .set_stack_index(crate::gdt::SYSCALL_IST_INDEX) .set_privilege_level(x86_64::PrivilegeLevel::Ring3); } @@ -158,7 +158,9 @@ pub extern "C" fn clock(mut regs: Registers, mut sf: InterruptStackFrame) { as_handler!(clock); pub extern "C" fn syscall(mut regs: Registers, mut sf: InterruptStackFrame) { - super::syscall::dispatcher(&mut regs, &mut sf); + x86_64::instructions::interrupts::without_interrupts(|| { + super::syscall::dispatcher(&mut regs, &mut sf); + }); } as_handler!(syscall); diff --git a/pkg/kernel/src/interrupt/syscall/mod.rs b/pkg/kernel/src/interrupt/syscall/mod.rs index 78f23af..4f849f7 100644 --- a/pkg/kernel/src/interrupt/syscall/mod.rs +++ b/pkg/kernel/src/interrupt/syscall/mod.rs @@ -21,6 +21,7 @@ pub enum Syscall { Allocate = 10, Deallocate = 11, Draw = 12, + WaitPid = 13, #[num_enum(default)] None = 255, } @@ -42,19 +43,20 @@ pub fn dispatcher(regs: &mut Registers, sf: &mut InterruptStackFrame) { ); match args.syscall { - Syscall::SpawnProcess => regs.set_rax(spawn_process(&args)), - Syscall::ExitProcess => exit_process(regs, sf), - Syscall::Read => regs.set_rax(sys_read(&args)), - Syscall::Write => regs.set_rax(sys_write(&args)), - Syscall::Open => {} - Syscall::Close => {} - Syscall::Stat => list_process(), - Syscall::Time => regs.set_rax(sys_clock() as usize), - Syscall::DirectoryList => list_dir(&args), - Syscall::Allocate => regs.set_rax(sys_allocate(&args)), - Syscall::Deallocate => sys_deallocate(&args), - Syscall::Draw => sys_draw(&args), - Syscall::None => {} + Syscall::SpawnProcess => regs.set_rax(spawn_process(&args)), + Syscall::ExitProcess => exit_process(&args, regs, sf), + Syscall::Read => regs.set_rax(sys_read(&args)), + Syscall::Write => regs.set_rax(sys_write(&args)), + Syscall::Open => {} + Syscall::Close => {} + Syscall::Stat => list_process(), + Syscall::Time => regs.set_rax(sys_clock() as usize), + Syscall::DirectoryList => list_dir(&args), + Syscall::Allocate => regs.set_rax(sys_allocate(&args)), + Syscall::Deallocate => sys_deallocate(&args), + Syscall::Draw => sys_draw(&args), + Syscall::WaitPid => regs.set_rax(sys_wait_pid(&args)), + Syscall::None => {} } } diff --git a/pkg/kernel/src/interrupt/syscall/service.rs b/pkg/kernel/src/interrupt/syscall/service.rs index a5cf9ae..2a01353 100644 --- a/pkg/kernel/src/interrupt/syscall/service.rs +++ b/pkg/kernel/src/interrupt/syscall/service.rs @@ -1,5 +1,6 @@ use core::alloc::Layout; +use crate::process::ProcessId; use crate::utils::Registers; use crate::{display::get_display_for_sure, utils::*}; use embedded_graphics::prelude::*; @@ -95,8 +96,8 @@ pub fn sys_write(args: &SyscallArgs) -> usize { } } -pub fn exit_process(regs: &mut Registers, sf: &mut InterruptStackFrame) { - crate::process::process_exit(regs, sf); +pub fn exit_process(args: &SyscallArgs, regs: &mut Registers, sf: &mut InterruptStackFrame) { + crate::process::process_exit(args.arg0 as isize, regs, sf); } pub fn list_process() { @@ -116,3 +117,9 @@ pub fn list_dir(args: &SyscallArgs) { pub fn get_handle(fd: u8) -> Option { crate::process::handle(fd) } + +pub fn sys_wait_pid(args: &SyscallArgs) -> usize { + let pid = ProcessId(args.arg0 as u16); + let ret = crate::process::wait_pid(pid); + ret as usize +} diff --git a/pkg/kernel/src/lib.rs b/pkg/kernel/src/lib.rs index 5c89688..2fcc8a6 100644 --- a/pkg/kernel/src/lib.rs +++ b/pkg/kernel/src/lib.rs @@ -7,6 +7,7 @@ #![feature(alloc_error_handler)] #![feature(type_alias_impl_trait)] #![feature(panic_info_message)] +#![feature(map_try_insert)] extern crate alloc; #[macro_use] diff --git a/pkg/kernel/src/main.rs b/pkg/kernel/src/main.rs index cbb77a8..def38b7 100644 --- a/pkg/kernel/src/main.rs +++ b/pkg/kernel/src/main.rs @@ -13,10 +13,13 @@ pub fn kernal_main(boot_info: &'static boot::BootInfo) -> ! { let mut executor = Executor::new(); - let sh_file = ggos::filesystem::try_get_file("/APP/SH").unwrap(); - let pid = ggos::process::spawn(&sh_file).unwrap(); - - executor.run(pid); + // TODO: use executor.spawn() to spawn kernel tasks + executor.run(spawn_init()); ggos::shutdown(boot_info); } + +pub fn spawn_init() -> ggos::process::ProcessId { + let sh_file = ggos::filesystem::try_get_file("/APP/SH").unwrap(); + ggos::process::spawn(&sh_file).unwrap() +} diff --git a/pkg/kernel/src/memory/gdt.rs b/pkg/kernel/src/memory/gdt.rs index 3db33fe..8b66b07 100644 --- a/pkg/kernel/src/memory/gdt.rs +++ b/pkg/kernel/src/memory/gdt.rs @@ -4,16 +4,26 @@ use x86_64::structures::tss::TaskStateSegment; use x86_64::VirtAddr; pub const DOUBLE_FAULT_IST_INDEX: u16 = 0; -pub const CONTEXT_SWITCH: u16 = 0; +pub const SYSCALL_IST_INDEX: u16 = 1; +pub const CONTEXT_SWITCH_IST_INDEX: u16 = 0; lazy_static! { static ref TSS: TaskStateSegment = { let mut tss = TaskStateSegment::new(); - tss.interrupt_stack_table[CONTEXT_SWITCH as usize] = { - const STACK_SIZE: usize = 4096; + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { + const STACK_SIZE: usize = 0x1000; static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); let stack_end = stack_start + STACK_SIZE; + info!("Double Fault IST: 0x{:016x}-0x{:016x}", stack_start.as_u64(), stack_end.as_u64()); + stack_end + }; + tss.interrupt_stack_table[SYSCALL_IST_INDEX as usize] = { + const STACK_SIZE: usize = 0x4000; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + info!("Syscall IST: 0x{:016x}-0x{:016x}", stack_start.as_u64(), stack_end.as_u64()); stack_end }; tss diff --git a/pkg/kernel/src/process/manager.rs b/pkg/kernel/src/process/manager.rs index 3d065c3..461567c 100644 --- a/pkg/kernel/src/process/manager.rs +++ b/pkg/kernel/src/process/manager.rs @@ -1,5 +1,6 @@ use super::*; use crate::utils::Registers; +use alloc::collections::BTreeMap; use alloc::format; use alloc::vec::Vec; use x86_64::structures::idt::InterruptStackFrame; @@ -16,15 +17,18 @@ pub struct ProcessManager { /// pid of the current running process cur_pid: ProcessId, processes: Vec, + exit_code: BTreeMap, } impl ProcessManager { pub fn new(init: Process) -> Self { let mut processes = Vec::::new(); + let exit_code = BTreeMap::new(); processes.push(init); Self { cur_pid: ProcessId(0), processes, + exit_code } } @@ -42,6 +46,14 @@ impl ProcessManager { .unwrap() } + pub fn current_pid(&self) -> ProcessId { + self.cur_pid + } + + pub fn add_child(&mut self, child: ProcessId) { + self.current_mut().add_child(child); + } + pub fn save_current(&mut self, regs: &mut Registers, sf: &mut InterruptStackFrame) { let current = self.current_mut(); if current.is_running() { @@ -65,6 +77,14 @@ impl ProcessManager { } } + pub fn wait_pid(&mut self, pid: ProcessId) -> isize { + if self.exit_code.contains_key(&pid) { + self.exit_code.remove(&pid).unwrap() + } else { + -1 + } + } + pub fn still_alive(&self, pid: ProcessId) -> bool { self.processes.iter().any(|x| x.pid() == pid) } @@ -140,14 +160,26 @@ impl ProcessManager { } pub fn print_process_list(&self) { - let mut output = String::from(" PID | Name | Ticks\n"); + let mut output = String::from(" PID | PPID | Name | Ticks\n"); for p in self.processes.iter() { output = output + format!("{}\n", p).as_str(); } print!("{}", output); } - pub fn kill(&mut self) { + pub fn kill(&mut self, ret: isize) { + debug!("Killing process {}", self.cur_pid); + + let p = self.current().parent(); + self.processes.retain(|p| !p.is_running()); + + if let Err(_) = self.exit_code.try_insert(self.cur_pid, ret) { + error!("Process {} already exited", self.cur_pid); + } + + if let Some(proc) = self.processes.iter_mut().find(|x| x.pid() == p) { + proc.remove_child(self.cur_pid); + } } } diff --git a/pkg/kernel/src/process/mod.rs b/pkg/kernel/src/process/mod.rs index 384f04c..23face3 100644 --- a/pkg/kernel/src/process/mod.rs +++ b/pkg/kernel/src/process/mod.rs @@ -34,7 +34,7 @@ pub enum ProgramStatus { } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct ProcessId(u16); +pub struct ProcessId(pub u16); impl ProcessId { pub fn new() -> Self { @@ -85,14 +85,20 @@ pub fn env(key: &str) -> Option { }) } -pub fn process_exit(regs: &mut Registers, sf: &mut InterruptStackFrame) { +pub fn process_exit(ret: isize, regs: &mut Registers, sf: &mut InterruptStackFrame) { x86_64::instructions::interrupts::without_interrupts(|| { let mut manager = get_process_manager_for_sure(); - manager.kill(); + manager.kill(ret); manager.switch_next(regs, sf); }) } +pub fn wait_pid(pid: ProcessId) -> isize { + x86_64::instructions::interrupts::without_interrupts(|| { + get_process_manager_for_sure().wait_pid(pid) + }) +} + pub fn handle(fd: u8) -> Option { x86_64::instructions::interrupts::without_interrupts(|| { get_process_manager_for_sure().current().handle(fd) @@ -137,12 +143,15 @@ pub fn spawn(file: &File) -> Result { let mut manager = get_process_manager_for_sure(); let parent = manager.current().pid(); - manager.spawn( + let pid = manager.spawn( &elf, file.entry.filename(), parent, Some(ProcessData::new()), - ) + ); + + pid }); + Ok(pid) } diff --git a/pkg/kernel/src/process/process.rs b/pkg/kernel/src/process/process.rs index 91d3ede..5aa5c77 100644 --- a/pkg/kernel/src/process/process.rs +++ b/pkg/kernel/src/process/process.rs @@ -132,7 +132,7 @@ impl Process { let page_table_addr = frame_alloc .allocate_frame() .expect("Cannot alloc page table for new process."); - debug!("Alloc page table for {}: {:?}", name, page_table_addr); + trace!("Alloc page table for {}: {:?}", name, page_table_addr); // 2. copy current page table to new page table unsafe { @@ -188,6 +188,18 @@ impl Process { } } + pub fn add_child(&mut self, child: ProcessId) { + self.children.push(child); + } + + pub fn remove_child(&mut self, child: ProcessId) { + self.children.retain(|c| *c != child); + } + + pub fn parent(&self) -> ProcessId { + self.parent + } + pub fn init_elf(&mut self, elf: &ElfFile) { let alloc = &mut *crate::memory::get_frame_alloc_for_sure(); @@ -236,8 +248,8 @@ impl core::fmt::Display for Process { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!( f, - " #{:-3}| {:10} | {}", - u16::from(self.pid), self.name, self.ticks_passed + " #{:-3} | #{:-3} | {:10} | {}", + u16::from(self.pid), u16::from(self.parent), self.name, self.ticks_passed )?; Ok(()) } diff --git a/pkg/kernel/src/tasks/mod.rs b/pkg/kernel/src/tasks/mod.rs index 47dc432..395c08a 100644 --- a/pkg/kernel/src/tasks/mod.rs +++ b/pkg/kernel/src/tasks/mod.rs @@ -7,11 +7,8 @@ use core::{ }; pub mod executor; - -// pub mod input; -// pub use input::{get_key, push_key}; - pub use executor::Executor; + pub struct Task { id: TaskId, future: Pin>>, diff --git a/pkg/kernel/src/utils/regs.rs b/pkg/kernel/src/utils/regs.rs index d7355a1..86fab4d 100644 --- a/pkg/kernel/src/utils/regs.rs +++ b/pkg/kernel/src/utils/regs.rs @@ -86,7 +86,6 @@ macro_rules! as_handler { pub extern "x86-interrupt" fn [<$fn _handler>](_sf: InterruptStackFrame) { unsafe { core::arch::asm!(" - cli push rbp push rax push rbx @@ -118,7 +117,6 @@ macro_rules! as_handler { pop rbx pop rax pop rbp - sti iretq", sym $fn, options(noreturn)); } diff --git a/pkg/lib/src/lib.rs b/pkg/lib/src/lib.rs index 0953e5c..41add3b 100644 --- a/pkg/lib/src/lib.rs +++ b/pkg/lib/src/lib.rs @@ -31,7 +31,8 @@ pub enum Syscall { DirectoryList = 9, Allocate = 10, Deallocate = 11, - Draw = 12 + Draw = 12, + WaitPid = 13, } #[macro_export] diff --git a/pkg/lib/src/syscall.rs b/pkg/lib/src/syscall.rs index ddf0864..580a2d7 100644 --- a/pkg/lib/src/syscall.rs +++ b/pkg/lib/src/syscall.rs @@ -24,24 +24,29 @@ pub fn sys_read(fd: u64, buf: &mut [u8]) -> Option { } pub fn sys_allocate(layout: &core::alloc::Layout) -> *mut u8 { - syscall!( - Syscall::Allocate, - layout as *const _ - ) as *mut u8 + syscall!(Syscall::Allocate, layout as *const _) as *mut u8 } pub fn sys_deallocate(ptr: *mut u8, layout: &core::alloc::Layout) -> usize { - syscall!( - Syscall::Deallocate, - ptr, - layout as *const _ - ) + syscall!(Syscall::Deallocate, ptr, layout as *const _) } pub fn sys_exit(code: usize) { syscall!(Syscall::ExitProcess, code); } +pub fn sys_wait_pid(pid: u16) -> isize { + loop { + let ret = syscall!(Syscall::WaitPid, pid as u64) as isize; + if !ret.is_negative() { + return ret; + } + unsafe { + core::arch::asm!("hlt"); + } + } +} + pub fn sys_time() -> NaiveDateTime { let time = syscall!(Syscall::Time) as i64; const BILLION: i64 = 1_000_000_000; @@ -49,7 +54,11 @@ pub fn sys_time() -> NaiveDateTime { } pub fn sys_list_dir(root: &str) { - syscall!(Syscall::DirectoryList, root.as_ptr() as u64, root.len() as u64); + syscall!( + Syscall::DirectoryList, + root.as_ptr() as u64, + root.len() as u64 + ); } pub fn sys_stat() { @@ -57,5 +66,9 @@ pub fn sys_stat() { } pub fn sys_spawn(path: &str) -> u16 { - syscall!(Syscall::SpawnProcess, path.as_ptr() as u64, path.len() as u64) as u16 + syscall!( + Syscall::SpawnProcess, + path.as_ptr() as u64, + path.len() as u64 + ) as u16 }