diff --git a/Cargo.lock b/Cargo.lock index 4384154..e303c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "gglib" -version = "0.2.0" +version = "0.3.0" dependencies = [ "chrono", ] @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "ggos_kernel" -version = "0.9.7" +version = "0.9.8" dependencies = [ "bit_field", "bitflags 2.0.1", @@ -272,7 +272,7 @@ dependencies = [ [[package]] name = "ggos_sh" -version = "0.4.0" +version = "0.5.0" dependencies = [ "gglib", ] diff --git a/Makefile b/Makefile index ac52333..bbe8e71 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ OVMF := tools/OVMF.fd ESP := esp BUILD_ARGS := -QEMU_ARGS := -serial stdio +QEMU_ARGS := -m 64M +QEMU_OUTPUT := -serial stdio MODE ?= release RUN_MODE ?= CUR_PATH := $(shell pwd) @@ -18,7 +19,7 @@ ifeq (${MODE}, release) endif ifeq (${RUN_MODE}, nographic) - QEMU_ARGS = -nographic + QEMU_OUTPUT = -nographic endif .PHONY: build run debug clean launch intdbg \ @@ -33,6 +34,7 @@ launch: -bios ${OVMF} \ -net none \ $(QEMU_ARGS) \ + $(QEMU_OUTPUT) \ -drive format=raw,file=fat:rw:${ESP} intdbg: @@ -40,13 +42,16 @@ intdbg: -bios ${OVMF} \ -net none \ $(QEMU_ARGS) \ - -drive format=raw,file=fat:rw:${ESP} -no-reboot -d int,cpu_reset + $(QEMU_OUTPUT) \ + -drive format=raw,file=fat:rw:${ESP} \ + -no-reboot -d int,cpu_reset debug: build @qemu-system-x86_64 \ -bios ${OVMF} \ -net none \ $(QEMU_ARGS) \ + $(QEMU_OUTPUT) \ -drive format=raw,file=fat:rw:${ESP} \ -s -S diff --git a/pkg/app/fact/src/main.rs b/pkg/app/fact/src/main.rs index 6678562..24eb3b7 100644 --- a/pkg/app/fact/src/main.rs +++ b/pkg/app/fact/src/main.rs @@ -31,6 +31,9 @@ fn main() -> usize { // calculate factorial let result = factorial(n); + // print system status + sys_stat(); + // print result println!("The factorial of {} under modulo {} is {}.", n, MOD, result); diff --git a/pkg/app/hello/src/main.rs b/pkg/app/hello/src/main.rs index 58382dd..7414c72 100644 --- a/pkg/app/hello/src/main.rs +++ b/pkg/app/hello/src/main.rs @@ -8,7 +8,7 @@ extern crate lib; fn main() -> usize { println!("Hello, world!!!"); let time = lib::sys_time(); - println!("Now at: {}", time); + println!("Now at: {} UTC", time); println!("Huge stack testing..."); diff --git a/pkg/app/sh/Cargo.toml b/pkg/app/sh/Cargo.toml index cef7312..44135ee 100644 --- a/pkg/app/sh/Cargo.toml +++ b/pkg/app/sh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ggos_sh" -version = "0.4.0" +version = "0.5.0" edition = "2021" authors = ["GZTime "] diff --git a/pkg/app/sh/src/services.rs b/pkg/app/sh/src/services.rs index 7049674..dbd92c8 100644 --- a/pkg/app/sh/src/services.rs +++ b/pkg/app/sh/src/services.rs @@ -51,7 +51,8 @@ pub fn cat(path: &str, root_dir: &str) { String::from(path) } else { format!("{}{}", root_dir, path) - }; + } + .to_ascii_uppercase(); let fd = sys_open(path.as_str(), FileMode::ReadOnly); @@ -85,30 +86,20 @@ pub fn cat(path: &str, root_dir: &str) { pub fn cd(path: &str, root_dir: &mut String) { if path.starts_with('/') { - *root_dir = String::from(path); - return; - } - - match path { - ".." => { - if root_dir.as_str() == "/" { - return; - } - root_dir.pop(); - let pos = root_dir.rfind('/').unwrap(); - *root_dir = root_dir[..=pos].to_string(); - } - "." => return, - _ => { - root_dir.push_str(path); + *root_dir = String::from(path).to_ascii_uppercase(); + if !root_dir.ends_with('/') { root_dir.push('/'); - *root_dir = root_dir.to_ascii_uppercase(); } + } else { + root_dir.push_str(path); + root_dir.push('/'); + *root_dir = root_dir.to_ascii_uppercase(); } + canonicalize(root_dir) } pub fn exec(path: &str, root_dir: &str) { - let path = format!("{}{}", root_dir, path); + let path = format!("{}{}", root_dir, path).to_ascii_uppercase(); let start = sys_time(); let pid = sys_spawn(path.as_str()); @@ -129,7 +120,7 @@ pub fn exec(path: &str, root_dir: &str) { } pub fn nohup(path: &str, root_dir: &str) { - let path = format!("{}{}", root_dir, path); + let path = format!("{}{}", root_dir, path).to_ascii_uppercase(); let pid = sys_spawn(path.as_str()); @@ -144,3 +135,40 @@ pub fn nohup(path: &str, root_dir: &str) { pub fn kill(pid: u16) { sys_kill(pid); } + +pub fn canonicalize(path: &mut String) { + // If the path is not absolute, return an error + if !path.starts_with('/') { + *path = String::from("/"); + return; + } + + // Create an empty string to store the canonicalized path + let mut canonical = String::from("/"); + + // Split the path by the separator and iterate over the segments + for segment in path.split('/') { + match segment { + "" | "." => {} + ".." => { + if canonical.len() > 1 { + canonical.pop(); + let last_index = canonical.rfind('/').unwrap_or(0); + canonical.truncate(last_index + 1); + } + } + _ => { + if canonical.len() > 1 { + canonical.push('/'); + } + canonical.push_str(segment); + } + } + } + + if canonical.len() > 1 { + canonical.push('/'); + } + + *path = canonical; +} diff --git a/pkg/kernel/Cargo.toml b/pkg/kernel/Cargo.toml index 875f45f..7a0d58f 100644 --- a/pkg/kernel/Cargo.toml +++ b/pkg/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ggos_kernel" -version = "0.9.7" +version = "0.9.8" 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/drivers/ata.rs b/pkg/kernel/src/drivers/ata.rs index 479db71..889916c 100644 --- a/pkg/kernel/src/drivers/ata.rs +++ b/pkg/kernel/src/drivers/ata.rs @@ -311,14 +311,16 @@ impl Drive { fs::Block::SIZE } - fn humanized_size(&self) -> (usize, String) { + fn humanized_size(&self) -> (usize, &'static str) { let size = self.block_size(); let count = self.block_count().unwrap(); let bytes = size * count; - if bytes >> 20 < 1000 { - (bytes >> 20, String::from("MiB")) + if bytes >> 20 < 1024 { + (bytes >> 20, "MiB") + } else if bytes >> 30 < 1024 { + (bytes >> 30, "GiB") } else { - (bytes >> 30, String::from("GiB")) + (bytes >> 40, "TiB") } } } diff --git a/pkg/kernel/src/drivers/input.rs b/pkg/kernel/src/drivers/input.rs index 8bd3dfd..d4d6bd0 100644 --- a/pkg/kernel/src/drivers/input.rs +++ b/pkg/kernel/src/drivers/input.rs @@ -18,7 +18,7 @@ pub fn init() { pub fn push_key(key: DecodedKey) { if let Some(queue) = get_input_buf() { if queue.push(key).is_err() { - warn!("Input buffer is full."); + warn!("Input buffer is full. Dropping key '{:?}'", key); } } } diff --git a/pkg/kernel/src/main.rs b/pkg/kernel/src/main.rs index dc1876a..107e7d5 100644 --- a/pkg/kernel/src/main.rs +++ b/pkg/kernel/src/main.rs @@ -13,7 +13,7 @@ pub fn kernel_main(boot_info: &'static boot::BootInfo) -> ! { let mut executor = Executor::new(); - // TODO: use executor.spawn() to spawn kernel tasks + // use executor.spawn() to spawn kernel tasks executor.run(spawn_init()); ggos::shutdown(boot_info); diff --git a/pkg/kernel/src/memory/allocator.rs b/pkg/kernel/src/memory/allocator.rs index cd6fe5a..7d04249 100644 --- a/pkg/kernel/src/memory/allocator.rs +++ b/pkg/kernel/src/memory/allocator.rs @@ -7,7 +7,7 @@ use x86_64::structures::paging::{ use x86_64::VirtAddr; pub const HEAP_START: usize = 0xFFFF_FF80_0000_0000; -pub const HEAP_SIZE: usize = 512 * 1024; // 512 KiB +pub const HEAP_SIZE: usize = 1024 * 1024; // 1 MiB #[global_allocator] pub static ALLOCATOR: LockedHeap = LockedHeap::empty(); diff --git a/pkg/kernel/src/memory/frames.rs b/pkg/kernel/src/memory/frames.rs index 019c3f1..494209c 100644 --- a/pkg/kernel/src/memory/frames.rs +++ b/pkg/kernel/src/memory/frames.rs @@ -16,6 +16,7 @@ type BootInfoFrameIter = impl Iterator; /// A FrameAllocator that returns usable frames from the bootloader's memory map. pub struct BootInfoFrameAllocator { + size: usize, frames: BootInfoFrameIter, used: usize, recycled: Vec, @@ -27,8 +28,9 @@ impl BootInfoFrameAllocator { /// This function is unsafe because the caller must guarantee that the passed /// memory map is valid. The main requirement is that all frames that are marked /// as `USABLE` in it are really unused. - pub unsafe fn init(memory_map: &MemoryMap, used: usize) -> Self { + pub unsafe fn init(memory_map: &MemoryMap, used: usize, size: usize) -> Self { BootInfoFrameAllocator { + size, frames: create_frame_iter(memory_map), used, recycled: Vec::new(), @@ -39,6 +41,10 @@ impl BootInfoFrameAllocator { self.used } + pub fn frames_total(&self) -> usize { + self.size + } + pub fn recycled_count(&self) -> usize { self.recycled.len() } diff --git a/pkg/kernel/src/memory/mod.rs b/pkg/kernel/src/memory/mod.rs index 832637f..a119f43 100644 --- a/pkg/kernel/src/memory/mod.rs +++ b/pkg/kernel/src/memory/mod.rs @@ -38,19 +38,23 @@ pub fn init(boot_info: &'static boot::BootInfo) { let (size, unit) = humanized_size(used as u64 * PAGE_SIZE); info!("Kernel Used Memory: {:>7.*} {}", 3, size, unit); + let size = used + usable_mem_size as usize; + unsafe { init_PAGE_TABLE(paging::init(physical_memory_offset)); - init_FRAME_ALLOCATOR(BootInfoFrameAllocator::init(memory_map, used)); + init_FRAME_ALLOCATOR(BootInfoFrameAllocator::init(memory_map, used, size)); } } -fn humanized_size(size: u64) -> (f64, &'static str) { +pub fn humanized_size(size: u64) -> (f64, &'static str) { let bytes = size as f64; - if bytes < 1024f64 { - (bytes, "B") - } else if (bytes / (1 << 10) as f64) < 1024f64 { + + // use 1000 to keep the max length of the number is 3 digits + if bytes < 1000f64 { + (bytes, " B") + } else if (bytes / (1 << 10) as f64) < 1000f64 { (bytes / (1 << 10) as f64, "KiB") - } else if (bytes / (1 << 20) as f64) < 1024f64 { + } else if (bytes / (1 << 20) as f64) < 1000f64 { (bytes / (1 << 20) as f64, "MiB") } else { (bytes / (1 << 30) as f64, "GiB") diff --git a/pkg/kernel/src/memory/user.rs b/pkg/kernel/src/memory/user.rs index 90cee63..52222f4 100644 --- a/pkg/kernel/src/memory/user.rs +++ b/pkg/kernel/src/memory/user.rs @@ -7,7 +7,7 @@ use x86_64::structures::paging::{ use x86_64::VirtAddr; pub const USER_HEAP_START: usize = 0x4000_0000_0000; -pub const USER_HEAP_SIZE: usize = 128 * 1024; // 128 KiB +pub const USER_HEAP_SIZE: usize = 512 * 1024; // 512 KiB const USER_HEAP_PAGE: usize = USER_HEAP_SIZE / crate::memory::PAGE_SIZE as usize; pub static USER_ALLOCATOR: LockedHeap = LockedHeap::empty(); diff --git a/pkg/kernel/src/process/manager.rs b/pkg/kernel/src/process/manager.rs index 21b7dcc..42dbfcc 100644 --- a/pkg/kernel/src/process/manager.rs +++ b/pkg/kernel/src/process/manager.rs @@ -2,7 +2,7 @@ use super::*; use crate::memory::{ allocator::{ALLOCATOR, HEAP_SIZE}, get_frame_alloc_for_sure, - user::{USER_ALLOCATOR, USER_HEAP_SIZE}, + user::{USER_ALLOCATOR, USER_HEAP_SIZE}, self, PAGE_SIZE, }; use crate::utils::Registers; use alloc::collections::BTreeMap; @@ -202,7 +202,7 @@ impl ProcessManager { } pub fn print_process_list(&self) { - let mut output = String::from(" PID | PPID | Name | Ticks | Status\n"); + let mut output = String::from(" PID | PPID | Process Name | Ticks | Memory | Status\n"); for p in self.processes.iter() { output += format!("{}\n", p).as_str(); } @@ -216,9 +216,10 @@ impl ProcessManager { let alloc = get_frame_alloc_for_sure(); let frames_used = alloc.frames_used(); let frames_recycled = alloc.recycled_count(); + let frames_total = alloc.frames_total(); output += format!( - "Heap : {:>7.*}/{:>7.*} KiB ({:>5.2}%)\n", + "System : {:>7.*} KiB/ {:>7.*} KiB ({:>5.2}%)\n", 2, heap_used as f64 / 1024f64, 2, @@ -228,7 +229,7 @@ impl ProcessManager { .as_str(); output += format!( - "User : {:>7.*}/{:>7.*} KiB ({:>5.2}%)\n", + "User : {:>7.*} KiB/ {:>7.*} KiB ({:>5.2}%)\n", 2, user_heap_used as f64 / 1024f64, 2, @@ -237,15 +238,18 @@ impl ProcessManager { ) .as_str(); + // put used/total frames in MiB + let (used_size, used_unit) = memory::humanized_size(frames_used as u64 * PAGE_SIZE); + let (tot_size, tot_unit) = memory::humanized_size(frames_total as u64 * PAGE_SIZE); + output += format!( - "Frames: {:>7.*}/{:>7.*} MiB ({:>5.2}%) [{}/{} recycled/used]\n", + "Memory : {:>7.*} {}/ {:>7.*} {} ({:>5.2}%) [{} recycled]\n", 2, - (frames_recycled * 4) as f64 / 1024f64, + used_size, used_unit, 2, - (frames_used * 4) as f64 / 1024f64, - frames_recycled as f64 / frames_used as f64 * 100.0, - frames_recycled, - frames_used + tot_size, tot_unit, + frames_used as f64 / frames_total as f64 * 100.0, + frames_recycled ) .as_str(); diff --git a/pkg/kernel/src/process/process.rs b/pkg/kernel/src/process/process.rs index 4fff5b3..d6286ea 100644 --- a/pkg/kernel/src/process/process.rs +++ b/pkg/kernel/src/process/process.rs @@ -2,7 +2,7 @@ use super::ProcessId; use super::*; use crate::filesystem::StdIO; use crate::memory::gdt::get_user_selector; -use crate::memory::*; +use crate::memory::{self, *}; use crate::utils::{Registers, RegistersValue, Resource}; use alloc::collections::btree_map::BTreeMap; use alloc::string::String; @@ -38,6 +38,8 @@ pub struct ProcessData { code_segments: Option>, stack_segment: Option, file_handles: BTreeMap, + pub code_memory_usage: usize, + pub stack_memory_usage: usize, } impl ProcessData { @@ -56,6 +58,8 @@ impl ProcessData { code_segments, stack_segment, file_handles, + code_memory_usage: 0, + stack_memory_usage: 0, } } @@ -73,11 +77,21 @@ impl ProcessData { pub fn set_stack(mut self, start: u64, size: u64) -> Self { let start = Page::containing_address(VirtAddr::new(start)); self.stack_segment = Some(Page::range(start, start + size)); + self.stack_memory_usage = size as usize; self } pub fn set_kernel_code(mut self, pages: &KernelPages) -> Self { - self.code_segments = Some(pages.into_iter().cloned().collect()); + let mut size = 0; + let owned_pages = pages + .iter() + .map(|page| { + size += page.count(); + PageRangeInclusive::from(page.clone()) + }) + .collect(); + self.code_segments = Some(owned_pages); + self.code_memory_usage = size; self } } @@ -282,11 +296,13 @@ impl Process { elf::map_range(addr.as_u64(), pages, page_table, alloc, true)?; let end_page = self.proc_data.stack_segment.unwrap().end; - - self.proc_data.stack_segment = Some(PageRange { + let new_stack = PageRange { start: start_page, end: end_page, - }); + }; + + self.proc_data.stack_memory_usage = new_stack.count(); + self.proc_data.stack_segment = Some(new_stack); Ok(()) } @@ -351,12 +367,17 @@ impl Process { // clone proc data let mut owned_proc_data = self.proc_data.clone(); // record new stack range - owned_proc_data.stack_segment = Some(Page::range( + let stack = Page::range( Page::containing_address(VirtAddr::new_truncate(new_stack_base)), Page::containing_address(VirtAddr::new_truncate( new_stack_base + stack_info.count() as u64 * Size4KiB::SIZE, )), - )); + ); + // use shared code segment, only record the new stack usage + owned_proc_data.stack_memory_usage = stack.count(); + owned_proc_data.code_memory_usage = 0; + owned_proc_data.stack_segment = Some(stack); + // create new process let mut child = Self { pid: ProcessId::new(), @@ -396,6 +417,10 @@ impl Process { self.children.clone() } + pub fn memory_usage(&self) -> usize { + self.proc_data.code_memory_usage + self.proc_data.stack_memory_usage + } + pub fn not_drop_page_table(&mut self) { unsafe { self.page_table_addr.0 = PhysFrame::from_start_address_unchecked(PhysAddr::new(0)) @@ -413,6 +438,14 @@ impl Process { let stack_segment = elf::map_range(STACT_INIT_BOT, STACK_DEF_PAGE, &mut page_table, alloc, true).unwrap(); + // record memory usage + self.proc_data.code_memory_usage = code_segments + .iter() + .map(|seg| seg.count()) + .fold(0, |acc, x| acc + x); + + self.proc_data.stack_memory_usage = stack_segment.count(); + self.page_table = Some(page_table); self.proc_data.code_segments = Some(code_segments); self.proc_data.stack_segment = Some(stack_segment); @@ -499,13 +532,16 @@ impl core::fmt::Debug for Process { impl core::fmt::Display for Process { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let (size, unit) = memory::humanized_size(self.memory_usage() as u64 * 4096); write!( f, - " #{:-3} | #{:-3} | {:13} | {:8} | {:?}", + " #{:-3} | #{:-3} | {:12} | {:7} | {:>5.1} {} | {:?}", u16::from(self.pid), u16::from(self.parent), self.name, self.ticks_passed, + size, + unit, self.status )?; Ok(()) diff --git a/pkg/lib/Cargo.toml b/pkg/lib/Cargo.toml index a7f72f7..7e18715 100644 --- a/pkg/lib/Cargo.toml +++ b/pkg/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gglib" -version = "0.2.0" +version = "0.3.0" edition = "2021" authors = ["GZTime "] diff --git a/pkg/lib/src/io.rs b/pkg/lib/src/io.rs index f3ce019..cd23918 100644 --- a/pkg/lib/src/io.rs +++ b/pkg/lib/src/io.rs @@ -57,6 +57,8 @@ impl Stdin { string.pop(); } } + // ignore other control characters + '\x00'..='\x1F' => {} c => { print!("{}", k); string.push(c);