Parcourir la source

增加内存分配日志监视器 (#424)

* 完成内存日志监视,并输出日志到文件
* 修复进程退出后,procfs查看进程status文件会崩溃的问题
* 修复signal唤醒进程的判断条件问题
LoGin il y a 1 an
Parent
commit
7b32f5080f
46 fichiers modifiés avec 2033 ajouts et 59 suppressions
  1. 1 0
      .gitignore
  2. 1 2
      .vscode/settings.json
  3. 5 1
      Makefile
  4. 8 4
      kernel/Cargo.toml
  5. 0 1
      kernel/build.rs
  6. 3 16
      kernel/crates/crc/src/lib.rs
  7. 18 0
      kernel/crates/kdepends/Cargo.toml
  8. 9 0
      kernel/crates/kdepends/src/lib.rs
  9. 9 0
      kernel/crates/klog_types/Cargo.toml
  10. 241 0
      kernel/crates/klog_types/src/lib.rs
  11. 1 1
      kernel/src/arch/x86_64/process/mod.rs
  12. 1 1
      kernel/src/arch/x86_64/smp/mod.rs
  13. 78 0
      kernel/src/debug/klog/mm.rs
  14. 1 0
      kernel/src/debug/klog/mod.rs
  15. 1 0
      kernel/src/debug/mod.rs
  16. 1 1
      kernel/src/driver/base/platform/platform_device.rs
  17. 1 1
      kernel/src/driver/tty/mod.rs
  18. 17 16
      kernel/src/filesystem/procfs/mod.rs
  19. 31 3
      kernel/src/ipc/signal.rs
  20. 3 2
      kernel/src/lib.rs
  21. 2 2
      kernel/src/libs/ida/src/lib.rs
  22. 36 2
      kernel/src/mm/allocator/kernel_allocator.rs
  23. 10 0
      kernel/src/process/mod.rs
  24. 6 0
      tools/Cargo.toml
  25. 9 0
      tools/Makefile
  26. 1 0
      tools/debugging/logmonitor/.gitignore
  27. 17 0
      tools/debugging/logmonitor/Cargo.toml
  28. 10 0
      tools/debugging/logmonitor/README.md
  29. 212 0
      tools/debugging/logmonitor/src/app.rs
  30. 38 0
      tools/debugging/logmonitor/src/backend/error.rs
  31. 12 0
      tools/debugging/logmonitor/src/backend/event.rs
  32. 122 0
      tools/debugging/logmonitor/src/backend/loader.rs
  33. 127 0
      tools/debugging/logmonitor/src/backend/mod.rs
  34. 113 0
      tools/debugging/logmonitor/src/backend/monitor/logset.rs
  35. 286 0
      tools/debugging/logmonitor/src/backend/monitor/mm.rs
  36. 45 0
      tools/debugging/logmonitor/src/backend/monitor/mod.rs
  37. 32 0
      tools/debugging/logmonitor/src/command.rs
  38. 6 0
      tools/debugging/logmonitor/src/constant/mod.rs
  39. 83 0
      tools/debugging/logmonitor/src/event.rs
  40. 35 0
      tools/debugging/logmonitor/src/handler.rs
  41. 25 0
      tools/debugging/logmonitor/src/lib.rs
  42. 51 0
      tools/debugging/logmonitor/src/logging.rs
  43. 98 0
      tools/debugging/logmonitor/src/main.rs
  44. 77 0
      tools/debugging/logmonitor/src/tui.rs
  45. 134 0
      tools/debugging/logmonitor/src/ui.rs
  46. 16 6
      tools/run-qemu.sh

+ 1 - 0
.gitignore

@@ -19,3 +19,4 @@ cppcheck.xml
 Cargo.lock
 .cache
 compile_commands.json
+/logs/

+ 1 - 2
.vscode/settings.json

@@ -177,11 +177,10 @@
     },
     "C_Cpp.errorSquiggles": "enabled",
     "esbonio.sphinx.confDir": "",
-    "rust-analyzer.cargo.target": "x86_64-unknown-none",
     "rust-analyzer.checkOnSave.allTargets": false,
     "rust-analyzer.linkedProjects": [
         "./kernel/Cargo.toml",
-        "./kernel/src/libs/ida/Cargo.toml"
+        "./tools/Cargo.toml",
     ],
     "rust-analyzer.check.overrideCommand": [
         "make",

+ 5 - 1
Makefile

@@ -1,4 +1,4 @@
-SUBDIRS = kernel user
+SUBDIRS = kernel user tools
 
 # ifndef $(EMULATOR)
 ifeq ($(EMULATOR), )
@@ -156,6 +156,10 @@ fmt:
 	@echo "格式化代码" 
 	FMT_CHECK=$(FMT_CHECK) $(MAKE) fmt -C kernel
 	FMT_CHECK=$(FMT_CHECK) $(MAKE) fmt -C user
+
+log-monitor:
+	@echo "启动日志监控"
+	@sh -c "cd tools/debugging/logmonitor && cargo run --release -- --log-dir $(ROOT_PATH)/logs/ --kernel $(ROOT_PATH)/bin/kernel/kernel.elf" 
 	
 help:
 	@echo "编译:"

+ 8 - 4
kernel/Cargo.toml

@@ -10,13 +10,17 @@ edition = "2021"
 crate-type = ["staticlib"]
 
 [workspace]
-members = [ "src/libs/intertrait" ]
+members = [ 
+    "crates/*",
+    "src/libs/intertrait" 
+]
 
 [features]
 default = ["backtrace"]
 # 内核栈回溯
 backtrace = []
 
+
 # 运行时依赖项
 [dependencies]
 x86 = "0.52.0"
@@ -25,8 +29,6 @@ bit_field = "0.10"
 bitflags = "1.3.2"
 bitfield-struct = "0.5.3"
 virtio-drivers = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/virtio-drivers.git", rev = "f1d1cbb" }
-# 一个无锁MPSC队列
-thingbuf = { version = "0.1.3", default-features = false, features = ["alloc"] }
 smoltcp = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/smoltcp.git", rev = "9027825", default-features = false, features = ["log", "alloc",  "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
 # num-traits 0.2.15
 num-traits = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
@@ -35,7 +37,6 @@ num-derive = "0.3"
 # 一个no_std的hashmap、hashset
 hashbrown = "0.13.2"
 elf = { version = "0.7.2", default-features = false }
-memoffset = "0.9.0"
 atomic_enum = "0.2.0"
 raw-cpuid = "11.0.1"
 acpi = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/acpi-rs.git", rev = "fb69243dcf" }
@@ -43,6 +44,9 @@ intertrait = { path = "src/libs/intertrait" }
 linkme = "0.2"
 ida = { path = "src/libs/ida" }
 mini-backtrace = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/mini-backtrace.git", rev = "ba98506685" }
+klog_types = { path = "crates/klog_types" }
+kdepends = { path = "crates/kdepends" }
+
 
 # 构建时依赖项
 [build-dependencies]

+ 0 - 1
kernel/build.rs

@@ -90,7 +90,6 @@ impl CFilesBuilder {
             #[cfg(target_arch = "x86_64")]
             c.define("__x86_64__", None);
         }
-
     }
 
     fn setup_global_include_dir(c: &mut Build) {

+ 3 - 16
kernel/crates/crc/src/lib.rs

@@ -1,22 +1,9 @@
 #![cfg_attr(not(test), no_std)]
-
+#![feature(const_for)]
+#![feature(const_mut_refs)]
+#![feature(const_trait_impl)]
 #[cfg(test)]
 extern crate std;
 
 pub mod crc64;
 pub mod tables;
-
-pub fn add(left: usize, right: usize) -> usize {
-    left + right
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn it_works() {
-        let result = add(2, 2);
-        assert_eq!(result, 4);
-    }
-}

+ 18 - 0
kernel/crates/kdepends/Cargo.toml

@@ -0,0 +1,18 @@
+[package]
+name = "kdepends"
+version = "0.1.0"
+edition = "2021"
+description = "需要导出的依赖项(为保持内核依赖版本与调试器依赖项版本相同,因此把公共依赖项写在这里)"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+memoffset = "0.9.0"
+crc = { path = "../crc" }
+
+# 一个无锁MPSC队列
+[dependencies.thingbuf]
+git = "https://git.mirrors.dragonos.org/DragonOS-Community/thingbuf.git"
+rev = "2dded730c3"
+default-features = false
+features = ["alloc", "static"]

+ 9 - 0
kernel/crates/kdepends/src/lib.rs

@@ -0,0 +1,9 @@
+#![no_std]
+
+#[allow(unused)]
+#[macro_use]
+pub extern crate thingbuf;
+
+pub extern crate memoffset;
+
+pub extern crate crc;

+ 9 - 0
kernel/crates/klog_types/Cargo.toml

@@ -0,0 +1,9 @@
+[package]
+name = "klog_types"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+kdepends = { path = "../kdepends" }

+ 241 - 0
kernel/crates/klog_types/src/lib.rs

@@ -0,0 +1,241 @@
+#![no_std]
+#![feature(const_refs_to_cell)]
+#![feature(const_size_of_val)]
+
+extern crate alloc;
+use core::{fmt::Debug, mem::size_of_val};
+
+use alloc::format;
+use kdepends::{memoffset::offset_of, thingbuf::StaticThingBuf};
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct AllocatorLog {
+    /// 日志的id
+    pub id: u64,
+    /// 日志类型
+    pub type_: AllocatorLogType,
+    /// 日志的时间
+    pub time: u64,
+
+    /// 日志的来源
+    pub source: LogSource,
+
+    /// 日志的来源pid
+    pub pid: Option<usize>,
+
+    pub checksum: u64,
+}
+
+impl AllocatorLog {
+    /// 创建一个日志
+    ///
+    /// ## 参数
+    ///
+    /// - `id`:日志的id
+    /// - `type_`:日志类型
+    /// - `source`:日志来源
+    /// - `pid`:日志来源的pid
+    /// - `time`:日志的时间
+    pub fn new(
+        id: u64,
+        type_: AllocatorLogType,
+        source: LogSource,
+        pid: Option<usize>,
+        time: u64,
+    ) -> Self {
+        let mut x = Self {
+            id,
+            type_,
+            time,
+            source,
+            pid,
+            checksum: 0,
+        };
+        let checksum = Self::calculate_checksum(&x);
+        x.checksum = checksum;
+        return x;
+    }
+
+    pub const fn zeroed() -> Self {
+        return Self {
+            id: 0,
+            type_: AllocatorLogType::Undefined,
+            time: 0,
+            source: LogSource::Undefined,
+            pid: None,
+            checksum: 0,
+        };
+    }
+
+    /// 计算日志的校验和
+    pub fn calculate_checksum(value: &Self) -> u64 {
+        let buf = unsafe {
+            core::slice::from_raw_parts(
+                value as *const _ as *const u8,
+                core::mem::size_of::<Self>() - core::mem::size_of::<u64>(),
+            )
+        };
+        let checksum = kdepends::crc::crc64::crc64_be(0, buf);
+        return checksum;
+    }
+
+    /// 验证日志的校验和
+    pub fn validate_checksum(&self) -> bool {
+        let checksum = Self::calculate_checksum(self);
+        return checksum == self.checksum;
+    }
+
+    /// 当前日志是否有效
+    pub fn is_valid(&self) -> bool {
+        if self.validate_checksum() == false {
+            return false;
+        }
+
+        if self.id == 0 {
+            return false;
+        }
+
+        return true;
+    }
+}
+
+impl PartialOrd for AllocatorLog {
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+        return self.id.partial_cmp(&other.id);
+    }
+}
+
+impl Ord for AllocatorLog {
+    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+        return self.id.cmp(&other.id);
+    }
+}
+
+/// 内存分配器日志类型
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum AllocatorLogType {
+    Undefined,
+    Alloc(AllocLogItem),
+    AllocZeroed(AllocLogItem),
+    Free(AllocLogItem),
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct AllocLogItem {
+    pub layout: core::alloc::Layout,
+    pub vaddr: Option<usize>,
+    pub paddr: Option<usize>,
+}
+
+impl AllocLogItem {
+    pub fn new(layout: core::alloc::Layout, vaddr: Option<usize>, paddr: Option<usize>) -> Self {
+        return Self {
+            layout,
+            vaddr,
+            paddr,
+        };
+    }
+}
+
+impl Debug for AllocLogItem {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("AllocLogItem")
+            .field("layout", &self.layout)
+            .field(
+                "vaddr",
+                &format_args!("{:#x}", *self.vaddr.as_ref().unwrap_or(&0)),
+            )
+            .field(
+                "paddr",
+                &format_args!("{:#x}", self.paddr.as_ref().unwrap_or(&0)),
+            )
+            .finish()
+    }
+}
+
+#[repr(u8)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum LogSource {
+    Undefined = 0,
+    Bump = 1,
+    Buddy = 2,
+    Slab = 3,
+}
+
+pub struct MMLogCycle;
+
+impl MMLogCycle {
+    pub const fn new() -> Self {
+        Self {}
+    }
+}
+
+impl kdepends::thingbuf::Recycle<AllocatorLog> for MMLogCycle {
+    fn new_element(&self) -> AllocatorLog {
+        AllocatorLog::zeroed()
+    }
+
+    fn recycle(&self, element: &mut AllocatorLog) {
+        *element = AllocatorLog::zeroed();
+    }
+}
+
+/// 内存分配器日志通道
+#[repr(C)]
+pub struct MMLogChannel<const CAP: usize> {
+    pub magic: u32,
+    /// 日志元素的大小
+    pub element_size: u32,
+    /// 日志通道每个槽的大小(字节)
+    pub slot_size: u32,
+    pub capacity: u64,
+    pub slots_offset: u64,
+    pub buf: StaticThingBuf<AllocatorLog, CAP, MMLogCycle>,
+}
+
+impl<const CAP: usize> Debug for MMLogChannel<CAP> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("MMLogChannel")
+            .field("magic", &format!("{:#x}", self.magic))
+            .field("element_size", &self.element_size)
+            .field("capacity", &self.capacity)
+            .field("slots_offset", &self.slots_offset)
+            .field(
+                "buf",
+                &format!(
+                    "StaticThingBuf<AllocatorLog, {}, MMLogCycle>",
+                    self.capacity
+                ),
+            )
+            .finish()
+    }
+}
+
+impl<const CAP: usize> MMLogChannel<CAP> {
+    /// 日志通道的魔数
+    pub const MM_LOG_CHANNEL_MAGIC: u32 = 0x4d4c4348;
+
+    /// 创建一个大小为`capacity`日志通道
+    pub const fn new(capacity: usize) -> Self {
+        let buffer = StaticThingBuf::with_recycle(MMLogCycle::new());
+        assert!(buffer.offset_of_slots() != 0);
+        let slot_total_size = size_of_val(&buffer) - buffer.offset_of_slots();
+        let slot_size = slot_total_size / capacity;
+        assert!(slot_size != 0);
+        assert!(slot_size > size_of_val(&AllocatorLog::zeroed()));
+
+        let r = Self {
+            magic: Self::MM_LOG_CHANNEL_MAGIC,
+            element_size: core::mem::size_of::<AllocatorLog>() as u32,
+            capacity: capacity as u64,
+            slot_size: slot_size as u32,
+            slots_offset: (offset_of!(MMLogChannel<CAP>, buf) + buffer.offset_of_slots()) as u64,
+            buf: buffer,
+        };
+
+        return r;
+    }
+}

+ 1 - 1
kernel/src/arch/x86_64/process/mod.rs

@@ -11,7 +11,7 @@ use alloc::{
     vec::Vec,
 };
 
-use memoffset::offset_of;
+use kdepends::memoffset::offset_of;
 use x86::{controlregs::Cr4, segmentation::SegmentSelector};
 
 use crate::{

+ 1 - 1
kernel/src/arch/x86_64/smp/mod.rs

@@ -4,7 +4,7 @@ use core::{
     sync::atomic::{compiler_fence, AtomicBool, Ordering},
 };
 
-use memoffset::offset_of;
+use kdepends::memoffset::offset_of;
 
 use crate::{
     arch::process::table::TSSManager, exception::InterruptArch,

+ 78 - 0
kernel/src/debug/klog/mm.rs

@@ -0,0 +1,78 @@
+extern crate klog_types;
+
+use core::intrinsics::unlikely;
+
+use klog_types::{AllocatorLog, AllocatorLogType, LogSource, MMLogChannel};
+
+use crate::{
+    arch::CurrentTimeArch,
+    process::{Pid, ProcessManager},
+    time::TimeArch,
+};
+
+/// 全局的内存分配器日志通道
+///
+/// 标记为`no_mangle`是为了让调试器能够找到这个变量
+#[no_mangle]
+static __MM_ALLOCATOR_LOG_CHANNEL: MMLogChannel<{ MMDebugLogManager::MAX_ALLOC_LOG_NUM }> =
+    MMLogChannel::new(MMDebugLogManager::MAX_ALLOC_LOG_NUM);
+
+/// 全局的内存分配器日志id分配器
+///
+/// id从1开始, 因为0是无效的id
+static __MM_DEBUG_LOG_IDA: ida::IdAllocator = ida::IdAllocator::new(1, usize::MAX);
+
+/// 记录内存分配器的日志
+///
+/// ## 参数
+///
+/// - `log_type`:日志类型
+/// - `source`:日志来源
+pub fn mm_debug_log(log_type: AllocatorLogType, source: LogSource) {
+    let pid = if unlikely(!ProcessManager::initialized()) {
+        Some(Pid::new(0))
+    } else {
+        Some(ProcessManager::current_pcb().pid())
+    };
+    MMDebugLogManager::log(log_type, source, pid);
+}
+
+#[derive(Debug)]
+pub(super) struct MMDebugLogManager;
+
+impl MMDebugLogManager {
+    /// 最大的内存分配器日志数量
+    pub const MAX_ALLOC_LOG_NUM: usize = 100000;
+
+    /// 记录内存分配器的日志
+    ///
+    /// ## 参数
+    ///
+    /// - `log_type`:日志类型
+    /// - `source`:日志来源
+    /// - `pid`:日志来源的pid
+    pub fn log(log_type: AllocatorLogType, source: LogSource, pid: Option<Pid>) {
+        let id = __MM_DEBUG_LOG_IDA.alloc().unwrap();
+        let log = AllocatorLog::new(
+            id as u64,
+            log_type,
+            source,
+            pid.map(|p| p.data()),
+            CurrentTimeArch::get_cycles() as u64,
+        );
+
+        let mut log = log;
+        loop {
+            let r = __MM_ALLOCATOR_LOG_CHANNEL.buf.push(log);
+            if let Err(r) = r {
+                // 如果日志通道满了,就把最早的日志丢弃
+                if __MM_ALLOCATOR_LOG_CHANNEL.buf.remaining() == 0 {
+                    __MM_ALLOCATOR_LOG_CHANNEL.buf.pop();
+                }
+                log = r.into_inner();
+            } else {
+                break;
+            }
+        }
+    }
+}

+ 1 - 0
kernel/src/debug/klog/mod.rs

@@ -0,0 +1 @@
+pub mod mm;

+ 1 - 0
kernel/src/debug/mod.rs

@@ -0,0 +1 @@
+pub mod klog;

+ 1 - 1
kernel/src/driver/base/platform/platform_device.rs

@@ -26,7 +26,7 @@ use crate::{
 use super::{super::device::DeviceState, platform_bus, platform_bus_device, CompatibleTable};
 
 /// 平台设备id分配器
-static PLATFORM_DEVID_IDA: IdAllocator = IdAllocator::new(i32::MAX as usize);
+static PLATFORM_DEVID_IDA: IdAllocator = IdAllocator::new(0, i32::MAX as usize);
 
 #[inline(always)]
 pub fn platform_device_manager() -> &'static PlatformDeviceManager {

+ 1 - 1
kernel/src/driver/tty/mod.rs

@@ -2,7 +2,7 @@ use core::intrinsics::unlikely;
 
 use alloc::string::String;
 
-use thingbuf::mpsc::{
+use kdepends::thingbuf::mpsc::{
     self,
     errors::{TryRecvError, TrySendError},
 };

+ 17 - 16
kernel/src/filesystem/procfs/mod.rs

@@ -179,23 +179,24 @@ impl ProcFSInode {
         );
         pdata.append(&mut format!("\nvrtime:\t{}", vrtime).as_bytes().to_owned());
 
-        let binding = pcb.basic().user_vm().unwrap();
-        let address_space_guard = binding.read();
-        // todo: 当前进程运行过程中占用内存的峰值
-        let hiwater_vm: u64 = 0;
-        // 进程代码段的大小
-        let text = (address_space_guard.end_code - address_space_guard.start_code) / 1024;
-        // 进程数据段的大小
-        let data = (address_space_guard.end_data - address_space_guard.start_data) / 1024;
-        drop(address_space_guard);
+        if let Some(user_vm) = pcb.basic().user_vm() {
+            let address_space_guard = user_vm.read();
+            // todo: 当前进程运行过程中占用内存的峰值
+            let hiwater_vm: u64 = 0;
+            // 进程代码段的大小
+            let text = (address_space_guard.end_code - address_space_guard.start_code) / 1024;
+            // 进程数据段的大小
+            let data = (address_space_guard.end_data - address_space_guard.start_data) / 1024;
+            drop(address_space_guard);
+            pdata.append(
+                &mut format!("\nVmPeak:\t{} kB", hiwater_vm)
+                    .as_bytes()
+                    .to_owned(),
+            );
+            pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned());
+            pdata.append(&mut format!("\nVmExe:\t{} kB", text).as_bytes().to_owned());
+        }
 
-        pdata.append(
-            &mut format!("\nVmPeak:\t{} kB", hiwater_vm)
-                .as_bytes()
-                .to_owned(),
-        );
-        pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned());
-        pdata.append(&mut format!("\nVmExe:\t{} kB", text).as_bytes().to_owned());
         pdata.append(
             &mut format!("\nflags: {:?}\n", pcb.flags().clone())
                 .as_bytes()

+ 31 - 3
kernel/src/ipc/signal.rs

@@ -50,10 +50,13 @@ impl Signal {
             kwarn!("No such process.");
             return retval;
         }
+
+        let pcb = pcb.unwrap();
         // println!("Target pcb = {:?}", pcb.as_ref().unwrap());
         compiler_fence(core::sync::atomic::Ordering::SeqCst);
         // 发送信号
-        retval = self.send_signal(info, pcb.unwrap(), PidType::PID);
+        retval = self.send_signal(info, pcb.clone(), PidType::PID);
+
         compiler_fence(core::sync::atomic::Ordering::SeqCst);
         return retval;
     }
@@ -282,8 +285,33 @@ fn signal_wake_up(pcb: Arc<ProcessControlBlock>, _guard: SpinLockGuard<SignalStr
     // 如果不是 fatal 的就只唤醒 stop 的进程来响应
     // kdebug!("signal_wake_up");
     // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核
-    let r = ProcessManager::wakeup_stop(&pcb);
-    if r.is_ok() {
+    let state = pcb.sched_info().state();
+    let mut wakeup_ok = true;
+    if state.is_blocked_interruptable() {
+        ProcessManager::wakeup(&pcb).unwrap_or_else(|e| {
+            wakeup_ok = false;
+            kwarn!(
+                "Current pid: {:?}, signal_wake_up target {:?} error: {:?}",
+                ProcessManager::current_pcb().pid(),
+                pcb.pid(),
+                e
+            );
+        });
+    } else if state.is_stopped() {
+        ProcessManager::wakeup_stop(&pcb).unwrap_or_else(|e| {
+            wakeup_ok = false;
+            kwarn!(
+                "Current pid: {:?}, signal_wake_up target {:?} error: {:?}",
+                ProcessManager::current_pcb().pid(),
+                pcb.pid(),
+                e
+            );
+        });
+    } else {
+        wakeup_ok = false;
+    }
+
+    if wakeup_ok {
         ProcessManager::kick(&pcb);
     } else {
         if fatal {

+ 3 - 2
kernel/src/lib.rs

@@ -39,6 +39,7 @@ mod arch;
 mod libs;
 #[macro_use]
 mod include;
+mod debug;
 mod driver; // 如果driver依赖了libs,应该在libs后面导出
 mod exception;
 mod filesystem;
@@ -60,17 +61,17 @@ extern crate bitflags;
 extern crate elf;
 #[macro_use]
 extern crate lazy_static;
-extern crate memoffset;
 extern crate num;
 #[macro_use]
 extern crate num_derive;
 extern crate smoltcp;
-extern crate thingbuf;
 #[macro_use]
 extern crate intertrait;
 #[cfg(target_arch = "x86_64")]
 extern crate x86;
 
+extern crate klog_types;
+
 use crate::mm::allocator::kernel_allocator::KernelAllocator;
 
 use crate::process::ProcessManager;

+ 2 - 2
kernel/src/libs/ida/src/lib.rs

@@ -16,9 +16,9 @@ pub struct IdAllocator {
 
 impl IdAllocator {
     /// 创建一个新的id分配器
-    pub const fn new(max_id: usize) -> Self {
+    pub const fn new(initial_id: usize, max_id: usize) -> Self {
         Self {
-            current_id: AtomicUsize::new(0),
+            current_id: AtomicUsize::new(initial_id),
             max_id,
             dead: AtomicBool::new(false),
         }

+ 36 - 2
kernel/src/mm/allocator/kernel_allocator.rs

@@ -1,5 +1,8 @@
+use klog_types::AllocLogItem;
+
 use crate::{
     arch::mm::LockedFrameAllocator,
+    debug::klog::mm::mm_debug_log,
     libs::align::page_align_up,
     mm::{MMArch, MemoryManagementArch, VirtAddr},
 };
@@ -81,15 +84,46 @@ impl LocalAlloc for KernelAllocator {
 /// 为内核slab分配器实现GlobalAlloc特性
 unsafe impl GlobalAlloc for KernelAllocator {
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        return self.local_alloc(layout);
+        let r = self.local_alloc(layout);
+        mm_debug_log(
+            klog_types::AllocatorLogType::Alloc(AllocLogItem::new(
+                layout.clone(),
+                Some(r as usize),
+                None,
+            )),
+            klog_types::LogSource::Buddy,
+        );
+
+        return r;
+
         // self.local_alloc_zeroed(layout, 0)
     }
 
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        self.local_alloc_zeroed(layout)
+        let r = self.local_alloc_zeroed(layout);
+
+        mm_debug_log(
+            klog_types::AllocatorLogType::AllocZeroed(AllocLogItem::new(
+                layout.clone(),
+                Some(r as usize),
+                None,
+            )),
+            klog_types::LogSource::Buddy,
+        );
+
+        return r;
     }
 
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        mm_debug_log(
+            klog_types::AllocatorLogType::Free(AllocLogItem::new(
+                layout.clone(),
+                Some(ptr as usize),
+                None,
+            )),
+            klog_types::LogSource::Buddy,
+        );
+
         self.local_dealloc(ptr, layout);
     }
 }

+ 10 - 0
kernel/src/process/mod.rs

@@ -121,6 +121,11 @@ impl ProcessManager {
         kinfo!("Process Manager initialized.");
     }
 
+    /// 判断进程管理器是否已经初始化完成
+    pub fn initialized() -> bool {
+        unsafe { __PROCESS_MANAGEMENT_INIT_DONE }
+    }
+
     /// 获取当前进程的pcb
     pub fn current_pcb() -> Arc<ProcessControlBlock> {
         if unlikely(unsafe { !__PROCESS_MANAGEMENT_INIT_DONE }) {
@@ -461,6 +466,11 @@ impl ProcessState {
         return matches!(self, ProcessState::Blocked(_));
     }
 
+    #[inline(always)]
+    pub fn is_blocked_interruptable(&self) -> bool {
+        return matches!(self, ProcessState::Blocked(true));
+    }
+
     #[inline(always)]
     pub fn is_exited(&self) -> bool {
         return matches!(self, ProcessState::Exited(_));

+ 6 - 0
tools/Cargo.toml

@@ -0,0 +1,6 @@
+[workspace]
+members = [
+    "debugging/logmonitor",
+]
+
+resolver = "2"

+ 9 - 0
tools/Makefile

@@ -0,0 +1,9 @@
+.PHONY: fmt
+fmt:
+	@cargo fmt --all $(FMT_CHECK)
+
+clean:
+	@cargo clean
+
+check:
+	@cargo check --all

+ 1 - 0
tools/debugging/logmonitor/.gitignore

@@ -0,0 +1 @@
+/logs/

+ 17 - 0
tools/debugging/logmonitor/Cargo.toml

@@ -0,0 +1,17 @@
+[package]
+name = "logmonitor"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+klog_types = { path = "../../../kernel/crates/klog_types" }
+crossterm = "0.26.1"
+ratatui = "0.24.0"
+clap = { version = "4.4.7", features = ["color", "error-context", "help", "std", "suggestions", "usage", "derive"] }
+rand = "0.8.5"
+goblin = "0.7.1"
+simple_logger = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/rust-simple_logger.git", "rev" = "36ab404868" }
+log = "0.4.20"
+lazy_static = "1.4.0"

+ 10 - 0
tools/debugging/logmonitor/README.md

@@ -0,0 +1,10 @@
+# 日志监视程序
+
+本程序监视DragonOS内核的环形缓冲区日志,并将其显示在屏幕上。
+
+
+## 使用方法
+
+1. 默认情况下,DragonOS内核已启用内存分配器的日志记录。
+2. 当qemu启动后,在DragonOS项目的根目录中,运行`make log-monitor`。
+3. 在`logs`目录查看日志文件。

+ 212 - 0
tools/debugging/logmonitor/src/app.rs

@@ -0,0 +1,212 @@
+use std::error;
+
+use rand::{distributions::Uniform, prelude::Distribution, rngs::ThreadRng};
+use ratatui::widgets::ListState;
+
+/// Application result type.
+pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>;
+
+/// Application.
+#[derive(Debug)]
+pub struct App<'a> {
+    /// APP的标题
+    pub title: &'a str,
+    /// Is the application running?
+    pub running: bool,
+
+    pub enhanced_graphics: bool,
+
+    /// counter
+    pub counter: u8,
+
+    pub tabs: TabsState<'a>,
+
+    pub memory_log_sparkline: Signal<RandomSignal>,
+
+    logs: Vec<String>,
+    pub stateful_logs: StatefulList<(&'a str, &'a str)>,
+
+    backend_log_receiver: Option<std::sync::mpsc::Receiver<String>>,
+}
+
+impl<'a> App<'a> {
+    /// Constructs a new instance of [`App`].
+    pub fn new(title: &'a str) -> Self {
+        let mut rand_signal = RandomSignal::new(0, 100);
+        let sparkline_points = rand_signal.by_ref().take(300).collect();
+        let sparkline = Signal {
+            source: rand_signal,
+            points: sparkline_points,
+            tick_rate: 1,
+        };
+
+        Self {
+            title,
+            running: true,
+            enhanced_graphics: true,
+            counter: 0,
+            tabs: TabsState::new(vec!["Tab0", "Tab1", "Tab2"]),
+            memory_log_sparkline: sparkline,
+            logs: Vec::new(),
+            stateful_logs: StatefulList::with_items(vec![]),
+            backend_log_receiver: None,
+        }
+    }
+
+    pub fn set_backend_log_receiver(&mut self, receiver: std::sync::mpsc::Receiver<String>) {
+        self.backend_log_receiver = Some(receiver);
+    }
+
+    /// Handles the tick event of the terminal.
+    pub fn tick(&mut self) {
+        self.memory_log_sparkline.on_tick();
+        self.handle_logs_on_tick();
+    }
+
+    /// 当到达tick时,处理日志
+    fn handle_logs_on_tick(&mut self) {
+        let logs_to_push = self
+            .backend_log_receiver
+            .as_ref()
+            .map(|rv| rv.try_iter().collect::<Vec<String>>());
+
+        if let Some(logs) = logs_to_push {
+            for log in logs {
+                self.push_log(log);
+            }
+        }
+    }
+
+    /// Set running to false to quit the application.
+    pub fn quit(&mut self) {
+        self.running = false;
+    }
+
+    pub fn increment_counter(&mut self) {
+        if let Some(res) = self.counter.checked_add(1) {
+            self.counter = res;
+        }
+    }
+
+    pub fn decrement_counter(&mut self) {
+        if let Some(res) = self.counter.checked_sub(1) {
+            self.counter = res;
+        }
+    }
+
+    pub fn push_log(&mut self, log: String) {
+        self.logs.push(log);
+    }
+
+    pub fn logs(&self) -> &Vec<String> {
+        &self.logs
+    }
+}
+
+#[derive(Debug)]
+pub struct TabsState<'a> {
+    pub titles: Vec<&'a str>,
+    pub index: usize,
+}
+
+impl<'a> TabsState<'a> {
+    pub fn new(titles: Vec<&'a str>) -> TabsState {
+        TabsState { titles, index: 0 }
+    }
+    pub fn next(&mut self) {
+        self.index = (self.index + 1) % self.titles.len();
+    }
+
+    pub fn previous(&mut self) {
+        if self.index > 0 {
+            self.index -= 1;
+        } else {
+            self.index = self.titles.len() - 1;
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct Signal<S: Iterator> {
+    source: S,
+    pub points: Vec<S::Item>,
+    tick_rate: usize,
+}
+
+impl<S> Signal<S>
+where
+    S: Iterator,
+{
+    fn on_tick(&mut self) {
+        for _ in 0..self.tick_rate {
+            self.points.remove(0);
+        }
+        self.points
+            .extend(self.source.by_ref().take(self.tick_rate));
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct RandomSignal {
+    distribution: Uniform<u64>,
+    rng: ThreadRng,
+}
+
+impl RandomSignal {
+    pub fn new(lower: u64, upper: u64) -> RandomSignal {
+        RandomSignal {
+            distribution: Uniform::new(lower, upper),
+            rng: rand::thread_rng(),
+        }
+    }
+}
+
+impl Iterator for RandomSignal {
+    type Item = u64;
+    fn next(&mut self) -> Option<u64> {
+        Some(self.distribution.sample(&mut self.rng))
+    }
+}
+
+#[derive(Debug)]
+pub struct StatefulList<T> {
+    pub state: ListState,
+    pub items: Vec<T>,
+}
+
+impl<T> StatefulList<T> {
+    pub fn with_items(items: Vec<T>) -> StatefulList<T> {
+        StatefulList {
+            state: ListState::default(),
+            items,
+        }
+    }
+
+    pub fn next(&mut self) {
+        let i = match self.state.selected() {
+            Some(i) => {
+                if i >= self.items.len() - 1 {
+                    0
+                } else {
+                    i + 1
+                }
+            }
+            None => 0,
+        };
+        self.state.select(Some(i));
+    }
+
+    pub fn previous(&mut self) {
+        let i = match self.state.selected() {
+            Some(i) => {
+                if i == 0 {
+                    self.items.len() - 1
+                } else {
+                    i - 1
+                }
+            }
+            None => 0,
+        };
+        self.state.select(Some(i));
+    }
+}

+ 38 - 0
tools/debugging/logmonitor/src/backend/error.rs

@@ -0,0 +1,38 @@
+use std::{error::Error, fmt::Display};
+
+#[derive(Debug)]
+pub enum BackendErrorKind {
+    FileNotFound,
+    KernelLoadError,
+}
+
+#[derive(Debug)]
+pub struct BackendError {
+    kind: BackendErrorKind,
+    message: Option<String>,
+}
+
+impl BackendError {
+    pub fn new(kind: BackendErrorKind, message: Option<String>) -> Self {
+        Self { kind, message }
+    }
+}
+
+impl Error for BackendError {}
+
+impl Display for BackendError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match &self.kind {
+            BackendErrorKind::FileNotFound => {
+                write!(f, "File not found: {:?}", self.message.as_ref().unwrap())
+            }
+            BackendErrorKind::KernelLoadError => {
+                write!(
+                    f,
+                    "Failed to load kernel: {:?}",
+                    self.message.as_ref().unwrap()
+                )
+            }
+        }
+    }
+}

+ 12 - 0
tools/debugging/logmonitor/src/backend/event.rs

@@ -0,0 +1,12 @@
+#[derive(Debug, Clone)]
+pub enum BackendEvent {
+    StartUp(StartUpEvent),
+}
+
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
+pub struct StartUpEvent {
+    started: bool,
+    message: String,
+    timestamp: std::time::Instant,
+}

+ 122 - 0
tools/debugging/logmonitor/src/backend/loader.rs

@@ -0,0 +1,122 @@
+use std::{ops::Deref, path::PathBuf};
+
+use goblin::elf::Sym;
+use log::info;
+
+use crate::app::AppResult;
+
+use super::error::{BackendError, BackendErrorKind};
+
+#[derive(Debug)]
+pub struct KernelLoader;
+
+impl KernelLoader {
+    pub fn load(kernel: &PathBuf) -> AppResult<KernelMetadata> {
+        info!("Loading kernel: {:?}", kernel);
+        let kernel_bytes = std::fs::read(kernel)?;
+        let elf = goblin::elf::Elf::parse(&kernel_bytes).map_err(|e| {
+            BackendError::new(
+                BackendErrorKind::KernelLoadError,
+                Some(format!("Failed to load kernel: {:?}", e)),
+            )
+        })?;
+        let mut result = KernelMetadata::new(kernel.clone());
+
+        info!("Parsing symbols...");
+        for sym in elf.syms.iter() {
+            let name = elf.strtab.get_at(sym.st_name).unwrap_or("");
+            result.add_symbol(sym.clone(), name.to_string());
+        }
+        info!("Parsed {} symbols", result.symbols().len());
+        info!("Loaded kernel: {:?}", kernel);
+        return Ok(result);
+    }
+}
+
+#[derive(Debug)]
+pub struct KernelMetadata {
+    pub kernel: PathBuf,
+    sym_collection: SymbolCollection,
+}
+
+impl KernelMetadata {
+    pub fn new(kernel: PathBuf) -> Self {
+        Self {
+            kernel,
+            sym_collection: SymbolCollection::new(),
+        }
+    }
+
+    pub fn symbols(&self) -> &[Symbol] {
+        &self.sym_collection.symbols
+    }
+
+    pub fn sym_collection(&self) -> &SymbolCollection {
+        &self.sym_collection
+    }
+
+    pub fn add_symbol(&mut self, sym: Sym, name: String) {
+        self.sym_collection.add_symbol(sym, name);
+    }
+}
+
+#[derive(Debug)]
+pub struct SymbolCollection {
+    symbols: Vec<Symbol>,
+}
+
+impl SymbolCollection {
+    pub fn new() -> Self {
+        Self {
+            symbols: Vec::new(),
+        }
+    }
+
+    pub fn add_symbol(&mut self, sym: Sym, name: String) {
+        self.symbols.push(Symbol::new(sym, name));
+    }
+
+    #[allow(dead_code)]
+    pub fn len(&self) -> usize {
+        self.symbols.len()
+    }
+
+    pub fn find_by_name(&self, name: &str) -> Option<&Symbol> {
+        self.symbols.iter().find(|sym| sym.name() == name)
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct Symbol {
+    sym: Sym,
+    name: String,
+}
+
+impl Symbol {
+    pub fn new(sym: Sym, name: String) -> Self {
+        Self { sym, name }
+    }
+
+    pub fn name(&self) -> &str {
+        &self.name
+    }
+
+    /// Returns the virtual address of the symbol.
+    #[allow(dead_code)]
+    pub fn vaddr(&self) -> usize {
+        self.sym.st_value as usize
+    }
+
+    /// Returns the offset of the symbol in the kernel memory.
+    pub fn memory_offset(&self) -> u64 {
+        self.sym.st_value & (!0xffff_8000_0000_0000)
+    }
+}
+
+impl Deref for Symbol {
+    type Target = Sym;
+
+    fn deref(&self) -> &Self::Target {
+        &self.sym
+    }
+}

+ 127 - 0
tools/debugging/logmonitor/src/backend/mod.rs

@@ -0,0 +1,127 @@
+use std::{
+    path::PathBuf,
+    sync::{mpsc, Arc, Mutex, RwLock, Weak},
+    thread::JoinHandle,
+};
+
+use log::info;
+
+use crate::{command::CommandLineArgs, event::Event};
+
+pub mod error;
+pub mod event;
+mod loader;
+mod monitor;
+
+#[derive(Debug)]
+pub struct AppBackend {
+    _command_line_args: CommandLineArgs,
+    _sender_to_frontend: mpsc::Sender<Event>,
+    data: Arc<Mutex<BackendData>>,
+    main_thread: RwLock<Option<std::thread::JoinHandle<()>>>,
+    /// All threads spawned by the backend.(Except the main thread)
+    threads: Mutex<Vec<JoinHandle<()>>>,
+}
+
+impl AppBackend {
+    pub fn new(command_line_args: CommandLineArgs, sender: mpsc::Sender<Event>) -> Arc<Self> {
+        let r = Arc::new(Self {
+            _command_line_args: command_line_args.clone(),
+            _sender_to_frontend: sender.clone(),
+            data: Arc::new(Mutex::new(BackendData::new())),
+            main_thread: RwLock::new(None),
+            threads: Mutex::new(Vec::new()),
+        });
+
+        r.data.lock().unwrap().kmem_path = Some(PathBuf::from(&command_line_args.kmem));
+
+        let main_thread = {
+            let cmdargs = command_line_args.clone();
+            let instance = r.clone();
+            let sd = sender.clone();
+            let dt = r.data.clone();
+            std::thread::spawn(move || {
+                let mut backend = BackendThread::new(cmdargs, sd, Arc::downgrade(&instance), dt);
+                backend.run_main();
+            })
+        };
+
+        *r.main_thread.write().unwrap() = Some(main_thread);
+
+        return r;
+    }
+}
+
+#[derive(Debug)]
+struct BackendData {
+    kernel_metadata: Option<loader::KernelMetadata>,
+    /// Path to the QEMU shm which contains the kernel memory.
+    kmem_path: Option<PathBuf>,
+}
+
+impl BackendData {
+    pub fn new() -> Self {
+        Self {
+            kernel_metadata: None,
+            kmem_path: None,
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct BackendThread {
+    _sender_to_frontend: mpsc::Sender<Event>,
+    command_line_args: CommandLineArgs,
+    shared_data: Arc<Mutex<BackendData>>,
+    backend_instance: Weak<AppBackend>,
+}
+
+impl BackendThread {
+    fn new(
+        command_line_args: CommandLineArgs,
+        sender: mpsc::Sender<Event>,
+        backend_instance: Weak<AppBackend>,
+        backend_data: Arc<Mutex<BackendData>>,
+    ) -> Self {
+        Self {
+            command_line_args,
+            _sender_to_frontend: sender,
+            backend_instance,
+            shared_data: backend_data,
+        }
+    }
+
+    pub fn run_main(&mut self) {
+        info!("DragonOS Log Monitor started.");
+        self.load_kernel();
+        self.run_mm_monitor();
+        loop {
+            // info!("BackendThread::run()");
+            std::thread::sleep(std::time::Duration::from_secs(1));
+        }
+    }
+
+    /// 启动内存管理监视器
+    fn run_mm_monitor(&mut self) {
+        info!("run_mm_monitor()");
+        let mm_monitor = monitor::mm::MMLogMonitor::new(self.shared_data.clone());
+        let handle = std::thread::spawn(move || {
+            mm_monitor.run();
+        });
+
+        self.backend_instance
+            .upgrade()
+            .unwrap()
+            .threads
+            .lock()
+            .unwrap()
+            .push(handle);
+    }
+
+    /// 加载DragonOS内核并初始化
+    fn load_kernel(&self) {
+        let res = loader::KernelLoader::load(&self.command_line_args.kernel)
+            .expect("Failed to load kernel");
+        self.shared_data.lock().unwrap().kernel_metadata = Some(res);
+    }
+}

+ 113 - 0
tools/debugging/logmonitor/src/backend/monitor/logset.rs

@@ -0,0 +1,113 @@
+use std::{collections::BTreeMap, fmt::Debug, fs::File, io::Write, path::PathBuf};
+
+use log::error;
+
+use crate::constant::CMD_ARGS;
+
+/// 日志集合
+///
+/// 所有的日志都会被存到这个集合中, 以便于进行各种操作
+///
+/// 日志集合的后端可以在日志插入前后做一些操作(需要实现[`LogSetBackend`])
+#[derive(Debug)]
+#[allow(dead_code)]
+pub struct LogSet<K, V> {
+    inner: BTreeMap<K, V>,
+    backend: Box<dyn LogSetBackend<K, V>>,
+    name: String,
+    file_path: PathBuf,
+    log_file: Option<File>,
+}
+
+#[allow(dead_code)]
+impl<K: Ord, V: Clone + PartialEq + Debug> LogSet<K, V> {
+    pub fn new(name: String, backend: Option<Box<dyn LogSetBackend<K, V>>>) -> Self {
+        let mut file_path = CMD_ARGS.read().unwrap().as_ref().unwrap().log_dir.clone();
+        file_path.push(format!("{}-{}.log", name, std::process::id()));
+
+        let log_file = File::create(&file_path).expect("Failed to create log file.");
+
+        Self {
+            inner: BTreeMap::new(),
+            backend: backend.unwrap_or_else(|| Box::new(DefaultBackend::new())),
+            name,
+            file_path,
+            log_file: Some(log_file),
+        }
+    }
+
+    pub fn insert(&mut self, key: K, value: V) {
+        let cloned_value = value.clone();
+        self.backend.before_insert(&self.name, &value);
+
+        let prev = self.inner.insert(key, value);
+        if let Some(prev) = prev {
+            if prev.ne(&cloned_value) {
+                error!(
+                    "LogSet::insert(): prev != cloned_value: prev: {:?}, cloned_value: {:?}",
+                    prev, cloned_value
+                );
+            }
+        } else {
+            self.log_file
+                .as_mut()
+                .map(|f| writeln!(f, "{:?}", cloned_value).ok());
+        }
+
+        self.backend.after_insert(&self.name, &cloned_value);
+    }
+
+    pub fn file_path(&self) -> &PathBuf {
+        &self.file_path
+    }
+
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    pub fn get(&self, key: &K) -> Option<&V> {
+        self.inner.get(key)
+    }
+
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
+        self.inner.get_mut(key)
+    }
+
+    pub fn remove(&mut self, key: &K) -> Option<V> {
+        self.inner.remove(key)
+    }
+
+    pub fn clear(&mut self) {
+        self.inner.clear();
+    }
+
+    pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
+        self.inner.iter()
+    }
+
+    pub fn contains_key(&self, key: &K) -> bool {
+        self.inner.contains_key(key)
+    }
+}
+
+/// 日志集合的后端, 用于在日志插入前后做一些操作
+pub trait LogSetBackend<K, V>: Debug {
+    fn before_insert(&mut self, _log_set_name: &str, _log: &V) {}
+
+    fn after_insert(&mut self, _log_set_name: &str, _log: &V) {}
+}
+
+#[derive(Debug)]
+struct DefaultBackend(());
+
+impl DefaultBackend {
+    pub const fn new() -> Self {
+        Self(())
+    }
+}
+
+impl<K, V> LogSetBackend<K, V> for DefaultBackend {
+    fn before_insert(&mut self, _log_set_name: &str, _log: &V) {}
+
+    fn after_insert(&mut self, _log_set_name: &str, _log: &V) {}
+}

+ 286 - 0
tools/debugging/logmonitor/src/backend/monitor/mm.rs

@@ -0,0 +1,286 @@
+use std::{
+    fs::File,
+    mem::size_of,
+    os::unix::prelude::FileExt,
+    path::PathBuf,
+    sync::{atomic::AtomicBool, mpsc, Arc, Mutex, Weak},
+    thread::JoinHandle,
+};
+
+use klog_types::{AllocatorLog, MMLogChannel};
+use log::info;
+
+use crate::backend::{
+    loader::Symbol,
+    monitor::{logset::LogSet, ObjectWrapper},
+    BackendData,
+};
+
+#[derive(Debug)]
+pub struct MMLogMonitor {
+    channel_symbol: Option<Symbol>,
+    shared_data: Arc<Mutex<BackendData>>,
+    /// All threads spawned by the mm log monitor.
+    threads: Mutex<Vec<JoinHandle<()>>>,
+    stop_child_threads: AtomicBool,
+    self_ref: Weak<Self>,
+
+    mm_log_receiver: Mutex<mpsc::Receiver<MMLogWorkerResult>>,
+    mm_log_sender: mpsc::Sender<MMLogWorkerResult>,
+}
+
+impl MMLogMonitor {
+    pub fn new(shared_data: Arc<Mutex<BackendData>>) -> Arc<Self> {
+        let guard = shared_data.lock().unwrap();
+        let mm_log_buffer_symbol: Option<Symbol> = guard
+            .kernel_metadata
+            .as_ref()
+            .map(|km| {
+                km.sym_collection()
+                    .find_by_name("__MM_ALLOCATOR_LOG_CHANNEL")
+                    .map(|s| s.clone())
+            })
+            .flatten();
+        drop(guard);
+
+        info!("mm_log_buffer_symbol: {:?}", mm_log_buffer_symbol);
+
+        let mm_log_worker_mpsc: (
+            mpsc::Sender<MMLogWorkerResult>,
+            mpsc::Receiver<MMLogWorkerResult>,
+        ) = mpsc::channel::<MMLogWorkerResult>();
+
+        let r = Self {
+            channel_symbol: mm_log_buffer_symbol,
+            shared_data,
+            threads: Mutex::new(Vec::new()),
+            stop_child_threads: AtomicBool::new(false),
+            self_ref: Weak::new(),
+            mm_log_receiver: Mutex::new(mm_log_worker_mpsc.1),
+            mm_log_sender: mm_log_worker_mpsc.0,
+        };
+
+        let r = Arc::new(r);
+        unsafe {
+            let self_ref = Arc::downgrade(&r);
+            let r_ptr = r.as_ref() as *const Self as *mut Self;
+            (*r_ptr).self_ref = self_ref;
+        }
+
+        return r;
+    }
+
+    pub fn run(&self) {
+        info!("MMLogMonitor::run()");
+
+        self.create_threads();
+
+        let mut logs_set =
+            LogSet::<usize, ObjectWrapper<AllocatorLog>>::new("mm_allocator_log".to_string(), None);
+
+        self.handle_logs(&mut logs_set);
+        // std::thread::sleep(std::time::Duration::from_micros(50));
+    }
+
+    fn handle_logs(&self, logs_set: &mut LogSet<usize, ObjectWrapper<AllocatorLog>>) {
+        let mut last_cnt = 0;
+        let mut last_time = std::time::Instant::now();
+        let mm_log_receiver = self.mm_log_receiver.lock().unwrap();
+        loop {
+            let logs = mm_log_receiver.recv();
+            if logs.is_err() {
+                return;
+            }
+
+            let logs = logs.unwrap();
+
+            for log in logs.logs {
+                logs_set.insert(log.id as usize, log);
+            }
+
+            let x = logs_set.len();
+            // info!("logs_set.len(): {}", x);
+            let current_time = std::time::Instant::now();
+            if current_time.duration_since(last_time).as_secs() >= 1 {
+                info!("memory log rate: {} logs/s", x - last_cnt);
+                last_cnt = x;
+                last_time = current_time;
+            }
+        }
+    }
+
+    // fn show_speed(&self, )
+
+    fn create_threads(&self) {
+        let km = self
+            .shared_data
+            .lock()
+            .unwrap()
+            .kmem_path
+            .clone()
+            .expect("DragonOS memory map file not specified.");
+        let monitor_weak = self.self_ref.clone();
+
+        let handle = std::thread::spawn(move || {
+            let mut monitor_thread = MMMonitorThread::new(monitor_weak, PathBuf::from(km));
+            monitor_thread.run();
+        });
+
+        self.threads.lock().unwrap().push(handle);
+    }
+}
+
+#[derive(Debug)]
+struct MMMonitorThread {
+    mm_log_monitor: Weak<MMLogMonitor>,
+    kmem_path: PathBuf,
+}
+
+impl MMMonitorThread {
+    /// Constructs a new instance of [`MMMonitorThread`].
+    ///
+    /// ## Parameters
+    ///
+    /// - `mm_log_monitor`: The [`MMLogMonitor`] instance.
+    /// - `kmem_path`: The path to the kernel memory file.
+    pub fn new(mm_log_monitor: Weak<MMLogMonitor>, kmem_path: PathBuf) -> Self {
+        Self {
+            mm_log_monitor,
+            kmem_path,
+        }
+    }
+
+    pub fn run(&mut self) {
+        info!("MMMonitorThread::run(): kmem_path: {:?}", self.kmem_path);
+
+        let mut kmem_file = self.open_kmem_file().expect("Failed to open kmem file.");
+
+        info!("Channel header loaded!");
+
+        let channel_header: ObjectWrapper<MMLogChannel<1>> = self.load_header(&mut kmem_file);
+
+        // 循环读取
+
+        self.process_logs(&mut kmem_file, &channel_header);
+    }
+
+    /// 处理内核内存分配日志
+    fn process_logs(&self, kmem_file: &mut File, channel_header: &ObjectWrapper<MMLogChannel<1>>) {
+        let cap = channel_header.capacity;
+        let mut buf = vec![0u8; (cap * channel_header.slot_size as u64) as usize];
+        let symbol = self
+            .mm_log_channel_symbol()
+            .expect("Failed to get memory log channel symbol.");
+
+        let sym_offset = symbol.memory_offset();
+
+        let slots_offset = channel_header.slots_offset + sym_offset;
+        let sender = self.mm_log_monitor.upgrade().unwrap().mm_log_sender.clone();
+        loop {
+            if self.should_stop() {
+                break;
+            }
+
+            let r = kmem_file
+                .read_at(&mut buf, slots_offset)
+                .expect("Failed to read kmem file.");
+            assert!(r == buf.len());
+
+            let mut logs = Vec::new();
+
+            for chunck in buf.chunks(channel_header.slot_size as usize) {
+                let log_item = {
+                    let log: Option<ObjectWrapper<AllocatorLog>> =
+                        ObjectWrapper::new(&chunck[0..channel_header.element_size as usize]);
+                    let log: ObjectWrapper<AllocatorLog> = log.unwrap();
+
+                    if log.is_valid() {
+                        Some(log)
+                    } else {
+                        None
+                    }
+                };
+                if let Some(log_item) = log_item {
+                    logs.push(log_item);
+                }
+            }
+            // 收集所有校验和正确的日志
+            // info!("valid_cnt: {}, invalid_cnt: {}", valid_cnt, invalid_cnt);
+            // info!("to send {} logs", logs.len());
+            if !logs.is_empty() {
+                sender.send(MMLogWorkerResult::new(logs)).unwrap();
+            }
+        }
+    }
+
+    fn open_kmem_file(&self) -> std::io::Result<std::fs::File> {
+        std::fs::OpenOptions::new().read(true).open(&self.kmem_path)
+    }
+
+    fn load_header(&self, kmem_file: &mut File) -> ObjectWrapper<MMLogChannel<1>> {
+        let mut buf = [0u8; size_of::<MMLogChannel<1>>()];
+        let symbol = self
+            .mm_log_channel_symbol()
+            .expect("Failed to get memory log channel symbol.");
+
+        let sym_offset = symbol.memory_offset();
+
+        let channel_header: Option<ObjectWrapper<MMLogChannel<1>>>;
+
+        loop {
+            let _r = kmem_file.read_at(&mut buf, sym_offset);
+
+            let header: ObjectWrapper<MMLogChannel<1>> =
+                ObjectWrapper::new(&buf).expect("Failed to parse MMLogChannel header.");
+            if header.magic == MMLogChannel::<1>::MM_LOG_CHANNEL_MAGIC {
+                info!("channel_header: {:?}", header);
+                channel_header = Some(header);
+                break;
+            } else {
+                info!("MM Log Channel not found... Maybe the kernel not started? Or the kernel version is not supported?");
+            }
+
+            std::thread::sleep(std::time::Duration::from_secs(1));
+        }
+
+        return channel_header.unwrap();
+    }
+
+    /// Get the symbol of the memory log channel.
+    fn mm_log_channel_symbol(&self) -> Option<Symbol> {
+        self.mm_log_monitor
+            .upgrade()
+            .unwrap()
+            .channel_symbol
+            .clone()
+    }
+
+    /// Check if the monitor worker thread should stop.
+    fn should_stop(&self) -> bool {
+        self.mm_log_monitor
+            .upgrade()
+            .map(|mm_log_monitor| {
+                mm_log_monitor
+                    .stop_child_threads
+                    .load(std::sync::atomic::Ordering::Relaxed)
+            })
+            .unwrap_or(true)
+    }
+}
+
+/// 内存日志监视器工作线程处理的结果
+#[derive(Debug)]
+struct MMLogWorkerResult {
+    logs: Vec<ObjectWrapper<AllocatorLog>>,
+}
+
+impl MMLogWorkerResult {
+    /// 创建一个新的内存日志监视器工作线程处理的结果
+    ///
+    /// ## 参数
+    ///
+    /// - `logs`:处理的日志
+    pub fn new(logs: Vec<ObjectWrapper<AllocatorLog>>) -> Self {
+        Self { logs }
+    }
+}

+ 45 - 0
tools/debugging/logmonitor/src/backend/monitor/mod.rs

@@ -0,0 +1,45 @@
+use std::{
+    fmt::Debug,
+    ops::{Deref, DerefMut},
+};
+
+pub mod logset;
+pub mod mm;
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct ObjectWrapper<T> {
+    object: Box<T>,
+}
+
+impl<T: Debug + Sized> ObjectWrapper<T> {
+    pub fn new(buf: &[u8]) -> Option<Self> {
+        if buf.len() != std::mem::size_of::<T>() {
+            println!(
+                "ObjectWrapper::new(): buf.len() '{}'  != std::mem::size_of::<T>(): '{}'",
+                buf.len(),
+                std::mem::size_of::<T>()
+            );
+            return None;
+        }
+        let x = unsafe { std::ptr::read(buf.as_ptr() as *const T) };
+
+        let object = Box::new(x);
+
+        // let object = ManuallyDrop::new(x);
+        Some(Self { object })
+    }
+}
+
+impl<T> DerefMut for ObjectWrapper<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.object
+    }
+}
+
+impl<T> Deref for ObjectWrapper<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.object
+    }
+}

+ 32 - 0
tools/debugging/logmonitor/src/command.rs

@@ -0,0 +1,32 @@
+use std::path::PathBuf;
+
+use clap::Parser;
+
+#[derive(Debug, Parser, Clone)]
+pub struct CommandLineArgs {
+    #[arg(short, long)]
+    /// The kernel ELF file to load.
+    pub kernel: PathBuf,
+
+    /// The kernel memory file to load.
+    #[arg(long, value_parser=kmem_file_parser, default_value = "/dev/shm/dragonos-qemu-shm.ram")]
+    pub kmem: String,
+
+    /// If set, the monitor will start the TUI.
+    #[arg(long, default_value = "false")]
+    pub tui: bool,
+
+    /// The directory to store the log files.
+    #[arg(long, default_value = "logs")]
+    pub log_dir: PathBuf,
+}
+
+/// 用于解析kmem参数的函数
+fn kmem_file_parser(s: &str) -> Result<String, String> {
+    log::warn!("kmem_file_parser: {}", s);
+    if s.len() == 0 {
+        return Ok("/dev/shm/dragonos-qemu-shm.ram".to_string());
+    } else {
+        return Ok(s.to_string());
+    }
+}

+ 6 - 0
tools/debugging/logmonitor/src/constant/mod.rs

@@ -0,0 +1,6 @@
+use std::sync::RwLock;
+
+use crate::command::CommandLineArgs;
+
+/// 启动时的命令行参数
+pub static CMD_ARGS: RwLock<Option<CommandLineArgs>> = RwLock::new(None);

+ 83 - 0
tools/debugging/logmonitor/src/event.rs

@@ -0,0 +1,83 @@
+use crate::app::AppResult;
+use crate::backend::event::BackendEvent;
+use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, MouseEvent};
+use std::sync::mpsc;
+use std::thread;
+use std::time::{Duration, Instant};
+
+/// Terminal events.
+#[derive(Clone, Debug)]
+pub enum Event {
+    /// Terminal tick.
+    Tick,
+    /// Key press.
+    Key(KeyEvent),
+    /// Mouse click/scroll.
+    Mouse(MouseEvent),
+    /// Terminal resize.
+    Resize(u16, u16),
+    Backend(BackendEvent),
+}
+
+/// Terminal event handler.
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct EventHandler {
+    /// Event sender channel.
+    sender: mpsc::Sender<Event>,
+    /// Event receiver channel.
+    receiver: mpsc::Receiver<Event>,
+    /// Event handler thread.
+    handler: thread::JoinHandle<()>,
+}
+
+impl EventHandler {
+    /// Constructs a new instance of [`EventHandler`].
+    pub fn new(tick_rate: u64) -> Self {
+        let tick_rate = Duration::from_millis(tick_rate);
+        let (sender, receiver) = mpsc::channel();
+        let handler = {
+            let sender = sender.clone();
+            thread::spawn(move || {
+                let mut last_tick = Instant::now();
+                loop {
+                    let timeout = tick_rate
+                        .checked_sub(last_tick.elapsed())
+                        .unwrap_or(tick_rate);
+
+                    if event::poll(timeout).expect("no events available") {
+                        match event::read().expect("unable to read event") {
+                            CrosstermEvent::Key(e) => sender.send(Event::Key(e)),
+                            CrosstermEvent::Mouse(e) => sender.send(Event::Mouse(e)),
+                            CrosstermEvent::Resize(w, h) => sender.send(Event::Resize(w, h)),
+                            _ => unimplemented!(),
+                        }
+                        .expect("failed to send terminal event")
+                    }
+
+                    if last_tick.elapsed() >= tick_rate {
+                        sender.send(Event::Tick).expect("failed to send tick event");
+                        last_tick = Instant::now();
+                    }
+                }
+            })
+        };
+        Self {
+            sender,
+            receiver,
+            handler,
+        }
+    }
+
+    /// Receive the next event from the handler thread.
+    ///
+    /// This function will always block the current thread if
+    /// there is no data available and it's possible for more data to be sent.
+    pub fn next(&self) -> AppResult<Event> {
+        Ok(self.receiver.recv()?)
+    }
+
+    pub fn sender(&self) -> mpsc::Sender<Event> {
+        self.sender.clone()
+    }
+}

+ 35 - 0
tools/debugging/logmonitor/src/handler.rs

@@ -0,0 +1,35 @@
+use crate::{
+    app::{App, AppResult},
+    backend::event::BackendEvent,
+};
+use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
+
+/// Handles the key events and updates the state of [`App`].
+pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
+    match key_event.code {
+        // Exit application on `ESC` or `q`
+        KeyCode::Esc | KeyCode::Char('q') => {
+            app.quit();
+        }
+        // Exit application on `Ctrl-C`
+        KeyCode::Char('c') | KeyCode::Char('C') => {
+            if key_event.modifiers == KeyModifiers::CONTROL {
+                app.quit();
+            }
+        }
+        // Counter handlers
+        KeyCode::Right => {
+            app.increment_counter();
+        }
+        KeyCode::Left => {
+            app.decrement_counter();
+        }
+        // Other handlers you could add here.
+        _ => {}
+    }
+    Ok(())
+}
+
+pub fn handle_backend_events(_backend_event: BackendEvent, _app: &mut App) -> AppResult<()> {
+    return Ok(());
+}

+ 25 - 0
tools/debugging/logmonitor/src/lib.rs

@@ -0,0 +1,25 @@
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+extern crate clap;
+
+extern crate lazy_static;
+
+/// Application.
+pub mod app;
+
+/// Terminal events handler.
+pub mod event;
+
+/// Widget renderer.
+pub mod ui;
+
+/// Terminal user interface.
+pub mod tui;
+
+pub mod backend;
+pub mod command;
+pub mod constant;
+/// Event handler.
+pub mod handler;
+pub mod logging;

+ 51 - 0
tools/debugging/logmonitor/src/logging.rs

@@ -0,0 +1,51 @@
+use std::sync::mpsc;
+
+use log::LevelFilter;
+use simple_logger::LogBackend;
+
+use crate::command::CommandLineArgs;
+
+/// Initialize the logging system.
+pub fn init(cmd_args: &CommandLineArgs) -> LoggingInitResult {
+    let mut builder = simple_logger::SimpleLogger::new().with_level(LevelFilter::Info);
+
+    let mut result = LoggingInitResult::new(None);
+
+    if cmd_args.tui {
+        let channel: (mpsc::Sender<String>, mpsc::Receiver<String>) = mpsc::channel::<String>();
+        builder = builder.with_backend(Box::new(TUILoggingBackend::new(channel.0)));
+        result.tui_receiver = Some(channel.1);
+    }
+
+    builder.init().expect("failed to initialize logging");
+
+    return result;
+}
+
+#[derive(Debug)]
+pub struct LoggingInitResult {
+    /// Logging backend receiver.
+    pub tui_receiver: Option<mpsc::Receiver<String>>,
+}
+
+impl LoggingInitResult {
+    pub fn new(tui_receiver: Option<mpsc::Receiver<String>>) -> Self {
+        Self { tui_receiver }
+    }
+}
+
+pub struct TUILoggingBackend {
+    sender: mpsc::Sender<String>,
+}
+
+impl TUILoggingBackend {
+    pub fn new(sender: mpsc::Sender<String>) -> Self {
+        Self { sender }
+    }
+}
+
+impl LogBackend for TUILoggingBackend {
+    fn log(&self, message: String) {
+        self.sender.send(message).ok();
+    }
+}

+ 98 - 0
tools/debugging/logmonitor/src/main.rs

@@ -0,0 +1,98 @@
+use clap::Parser;
+use logmonitor::app::{App, AppResult};
+use logmonitor::command::{self, CommandLineArgs};
+use logmonitor::constant::CMD_ARGS;
+use logmonitor::event::{Event, EventHandler};
+use logmonitor::handler::{handle_backend_events, handle_key_events};
+use logmonitor::logging::LoggingInitResult;
+use logmonitor::tui::Tui;
+use ratatui::backend::CrosstermBackend;
+use ratatui::Terminal;
+use std::io;
+
+extern crate log;
+
+fn main() -> AppResult<()> {
+    let command_line_args = command::CommandLineArgs::parse();
+    *CMD_ARGS.write().unwrap() = Some(command_line_args.clone());
+    println!("{:?}", command_line_args);
+    prepare_env();
+
+    let logging_init_result = logmonitor::logging::init(&command_line_args);
+    if !command_line_args.tui {
+        return start_headless_app(command_line_args, logging_init_result);
+    } else {
+        return start_tui_app(command_line_args, logging_init_result);
+    }
+}
+
+fn prepare_env() {
+    // 创建日志文件夹
+    let p = CMD_ARGS.read().unwrap().clone();
+    let log_dir = p.unwrap().log_dir;
+    std::fs::create_dir_all(log_dir).expect("Failed to create log directory.");
+}
+
+/// 启动无界面应用
+fn start_headless_app(
+    cmdargs: CommandLineArgs,
+    _logging_init_result: LoggingInitResult,
+) -> AppResult<()> {
+    let mut app = App::new("DragonOS Log Monitor");
+    let events = EventHandler::new(250);
+    let _app_backend = logmonitor::backend::AppBackend::new(cmdargs.clone(), events.sender());
+
+    while app.running {
+        match events.next()? {
+            Event::Tick => app.tick(),
+            Event::Key(key_event) => handle_key_events(key_event, &mut app)?,
+            Event::Mouse(_) => {}
+            Event::Resize(_, _) => {}
+            Event::Backend(e) => {
+                handle_backend_events(e, &mut app)?;
+            }
+        }
+    }
+    println!("Headless mode not implemented yet.");
+    Ok(())
+}
+
+/// 启动TUI应用
+fn start_tui_app(
+    cmdargs: CommandLineArgs,
+    logging_init_result: LoggingInitResult,
+) -> AppResult<()> {
+    // Create an application.
+    let mut app = App::new("DragonOS Log Monitor");
+    if let Some(receiver) = logging_init_result.tui_receiver {
+        app.set_backend_log_receiver(receiver);
+    }
+
+    // Initialize the terminal user interface.
+    let backend = CrosstermBackend::new(io::stderr());
+    let terminal = Terminal::new(backend)?;
+    let events = EventHandler::new(250);
+    let mut tui = Tui::new(terminal, events);
+    tui.init()?;
+    let _app_backend = logmonitor::backend::AppBackend::new(cmdargs.clone(), tui.events.sender());
+
+    // Start the main loop.
+    while app.running {
+        // Render the user interface.
+        tui.draw(&mut app)?;
+        // Handle events.
+        match tui.events.next()? {
+            Event::Tick => app.tick(),
+            Event::Key(key_event) => handle_key_events(key_event, &mut app)?,
+            Event::Mouse(_) => {}
+            Event::Resize(_, _) => {}
+            Event::Backend(e) => {
+                handle_backend_events(e, &mut app)?;
+            }
+        }
+    }
+
+    // Exit the user interface.
+    tui.exit()?;
+    Ok(())
+}

+ 77 - 0
tools/debugging/logmonitor/src/tui.rs

@@ -0,0 +1,77 @@
+use crate::app::{App, AppResult};
+use crate::event::EventHandler;
+use crate::ui;
+use crossterm::event::DisableMouseCapture;
+use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
+use std::io;
+use std::panic;
+
+use ratatui::backend::Backend;
+use ratatui::Terminal;
+
+/// Representation of a terminal user interface.
+///
+/// It is responsible for setting up the terminal,
+/// initializing the interface and handling the draw events.
+#[derive(Debug)]
+pub struct Tui<B: Backend> {
+    /// Interface to the Terminal.
+    terminal: Terminal<B>,
+    /// Terminal event handler.
+    pub events: EventHandler,
+}
+
+impl<B: Backend> Tui<B> {
+    /// Constructs a new instance of [`Tui`].
+    pub fn new(terminal: Terminal<B>, events: EventHandler) -> Self {
+        Self { terminal, events }
+    }
+
+    /// Initializes the terminal interface.
+    ///
+    /// It enables the raw mode and sets terminal properties.
+    pub fn init(&mut self) -> AppResult<()> {
+        terminal::enable_raw_mode()?;
+        crossterm::execute!(io::stderr(), EnterAlternateScreen, DisableMouseCapture)?;
+
+        // Define a custom panic hook to reset the terminal properties.
+        // This way, you won't have your terminal messed up if an unexpected error happens.
+        let panic_hook = panic::take_hook();
+        panic::set_hook(Box::new(move |panic| {
+            Self::reset().expect("failed to reset the terminal");
+            panic_hook(panic);
+        }));
+
+        self.terminal.hide_cursor()?;
+        self.terminal.clear()?;
+        Ok(())
+    }
+
+    /// [`Draw`] the terminal interface by [`rendering`] the widgets.
+    ///
+    /// [`Draw`]: ratatui::Terminal::draw
+    /// [`rendering`]: crate::ui:render
+    pub fn draw(&mut self, app: &mut App) -> AppResult<()> {
+        self.terminal.draw(|frame| ui::render(app, frame))?;
+        Ok(())
+    }
+
+    /// Resets the terminal interface.
+    ///
+    /// This function is also used for the panic hook to revert
+    /// the terminal properties if unexpected errors occur.
+    fn reset() -> AppResult<()> {
+        terminal::disable_raw_mode()?;
+        crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?;
+        Ok(())
+    }
+
+    /// Exits the terminal interface.
+    ///
+    /// It disables the raw mode and reverts back the terminal properties.
+    pub fn exit(&mut self) -> AppResult<()> {
+        Self::reset()?;
+        self.terminal.show_cursor()?;
+        Ok(())
+    }
+}

+ 134 - 0
tools/debugging/logmonitor/src/ui.rs

@@ -0,0 +1,134 @@
+use ratatui::{
+    prelude::{Constraint, Layout, Rect},
+    style::{Color, Modifier, Style},
+    symbols,
+    text::{self, Span, Text},
+    widgets::{Block, Borders, List, ListItem, Sparkline, Tabs},
+    Frame,
+};
+
+use crate::app::App;
+
+/// Renders the user interface widgets.
+pub fn render(app: &mut App, frame: &mut Frame) {
+    // This is where you add new widgets.
+    // See the following resources:
+    // - https://docs.rs/ratatui/latest/ratatui/widgets/index.html
+    // - https://github.com/ratatui-org/ratatui/tree/master/examples
+    // frame.render_widget(
+    //     Paragraph::new(format!(
+    //         "This is a tui template.\n\
+    //             Press `Esc`, `Ctrl-C` or `q` to stop running.\n\
+    //             Press left and right to increment and decrement the counter respectively.\n\
+    //             Counter: {}",
+    //         app.counter
+    //     ))
+    //     .block(
+    //         Block::default()
+    //             .title("Template")
+    //             .title_alignment(Alignment::Center)
+    //             .borders(Borders::ALL)
+    //             .border_type(BorderType::Rounded),
+    //     )
+    //     .style(Style::default().fg(Color::Cyan).bg(Color::Black))
+    //     .alignment(Alignment::Center),
+    //     frame.size(),
+    // )
+
+    let chunks = Layout::default()
+        .constraints([Constraint::Length(3), Constraint::Min(0)])
+        .split(frame.size());
+    let titles = app
+        .tabs
+        .titles
+        .iter()
+        .map(|t| text::Line::from(Span::styled(*t, Style::default().fg(Color::Green))))
+        .collect();
+    let tabs = Tabs::new(titles)
+        .block(Block::default().borders(Borders::ALL).title(app.title))
+        .highlight_style(Style::default().fg(Color::Yellow))
+        .select(app.tabs.index);
+    frame.render_widget(tabs, chunks[0]);
+
+    match app.tabs.index {
+        0 => draw_first_tab(frame, app, chunks[1]),
+        _ => {}
+    }
+}
+
+fn draw_first_tab(f: &mut Frame, app: &mut App, area: Rect) {
+    let chunks = Layout::default()
+        .constraints([
+            Constraint::Min(1),
+            Constraint::Min(3),
+            Constraint::Length(7),
+        ])
+        .split(area);
+    draw_memory_logging_speed_gauges(f, app, chunks[0]);
+    // draw_charts(f, app, chunks[1]);
+    draw_footer(f, app, chunks[2]);
+}
+
+/// 绘制内存日志产生数量的图表
+fn draw_memory_logging_speed_gauges(f: &mut Frame, app: &mut App, area: Rect) {
+    let chunks = Layout::default()
+        .constraints([Constraint::Length(3)])
+        .margin(1)
+        .split(area);
+    let block = Block::default().borders(Borders::ALL).title("Speed:");
+    f.render_widget(block, area);
+
+    let sparkline = Sparkline::default()
+        .block(Block::default().title("Memory Log Speed:"))
+        .style(Style::default().fg(Color::Green))
+        .data(&app.memory_log_sparkline.points)
+        .bar_set(if app.enhanced_graphics {
+            symbols::bar::NINE_LEVELS
+        } else {
+            symbols::bar::THREE_LEVELS
+        });
+    f.render_widget(sparkline, chunks[0]);
+}
+
+fn draw_footer(f: &mut Frame, app: &mut App, area: Rect) {
+    let _block = Block::default().borders(Borders::ALL).title(Span::styled(
+        "Logs",
+        Style::default()
+            .fg(Color::Magenta)
+            .add_modifier(Modifier::BOLD),
+    ));
+
+    let info_style = Style::default().fg(Color::Blue);
+    let warning_style = Style::default().fg(Color::Yellow);
+    let error_style = Style::default().fg(Color::Magenta);
+    let critical_style = Style::default().fg(Color::Red);
+
+    let binding = app.logs().clone();
+    let log_list = binding
+        .iter()
+        .map(|log_str| {
+            let _style = match log_str {
+                log if log.contains("INFO") => info_style,
+                log if log.contains("WARNING") => warning_style,
+                log if log.contains("ERROR") => error_style,
+                log if log.contains("CRITICAL") => critical_style,
+                _ => Style::default().fg(Color::White),
+            };
+
+            // println!("log_str: {}", log_str);
+
+            ListItem::new(Text::from(log_str.clone()))
+        })
+        .collect::<Vec<ListItem>>();
+
+    let items_num = 5;
+    let list_to_show = log_list.split_at(if log_list.len() > items_num {
+        log_list.len() - items_num
+    } else {
+        0
+    });
+
+    let logs =
+        List::new(list_to_show.1).block(Block::default().borders(Borders::ALL).title("List"));
+    f.render_stateful_widget(logs, area, &mut app.stateful_logs.state);
+}

+ 16 - 6
tools/run-qemu.sh

@@ -51,6 +51,9 @@ fi
 QEMU=qemu-system-x86_64
 QEMU_DISK_IMAGE="../bin/disk.img"
 QEMU_MEMORY="512M"
+QEMU_MEMORY_BACKEND="dragonos-qemu-shm.ram"
+QEMU_MEMORY_BACKEND_PATH_PREFIX="/dev/shm"
+QEMU_SHM_OBJECT="-object memory-backend-file,size=${QEMU_MEMORY},id=${QEMU_MEMORY_BACKEND},mem-path=${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND},share=on "
 QEMU_SMP="2,cores=2,threads=1,sockets=1"
 QEMU_MONITOR="stdio"
 QEMU_TRACE="${qemu_trace_std}"
@@ -65,17 +68,20 @@ if [ -n "${qemu_accel}" ]; then
     QEMU_ACCELARATE="-machine accel=${qemu_accel} -enable-kvm "
 fi
 
+QEMU_MACHINE=" -machine q35,memory-backend=${QEMU_MEMORY_BACKEND} "
+
 # ps: 下面这条使用tap的方式,无法dhcp获取到ip,暂时不知道为什么
-# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine q35 "
-QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4  -machine q35 " 
+# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 "
+QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 " 
 # E1000E
-# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine q35 " 
+# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 " 
 QEMU_ARGUMENT="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d -monitor ${QEMU_MONITOR} -d ${qemu_trace_std} "
 
-QEMU_ARGUMENT+="-s -S -cpu ${QEMU_CPU_FEATURES} -rtc ${QEMU_RTC_CLOCK} -serial ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES}"
-
+QEMU_ARGUMENT+="-s -S ${QEMU_MACHINE} -cpu ${QEMU_CPU_FEATURES} -rtc ${QEMU_RTC_CLOCK} -serial ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES}"
+QEMU_ARGUMENT+=" ${QEMU_SHM_OBJECT} "
 QEMU_ARGUMENT+=" ${QEMU_ACCELARATE} "
 
+
 if [ $flag_can_run -eq 1 ]; then
   while true;do
     case "$1" in
@@ -100,6 +106,9 @@ if [ $flag_can_run -eq 1 ]; then
       esac 
   done 
 
+# 删除共享内存
+sudo rm -rf ${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND}
+
 if [ ${BIOS_TYPE} == uefi ] ;then
   if [ ${ARCH} == x86_64 ] ;then
     sudo ${QEMU} -bios arch/x86_64/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}
@@ -109,7 +118,8 @@ if [ ${BIOS_TYPE} == uefi ] ;then
 else
   sudo ${QEMU} ${QEMU_ARGUMENT}
 fi
-
+# 删除共享内存
+sudo rm -rf ${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND}
 else
   echo "不满足运行条件"
 fi