Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions kernel/src/debug/klog/loglevel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
//! 内核日志级别管理模块
//!
//! 提供类似Linux内核的loglevel功能,支持通过cmdline参数和procfs接口
//! 动态控制内核日志输出级别。

use core::sync::atomic::{AtomicU8, Ordering};

use system_error::SystemError;

use crate::init::cmdline::{KernelCmdlineKV, KernelCmdlineParameter, KCMDLINE_PARAM_KV};

/// 全局内核日志级别配置
///
/// 遵循Linux内核语义:
/// - console_loglevel: 控制台输出级别,只有级别小于等于此值的消息才会输出
/// - default_message_loglevel: 默认消息级别
/// - minimum_console_loglevel: 最小控制台级别
/// - default_console_loglevel: 默认控制台级别
pub static KERNEL_LOG_LEVEL: KernelLogLevel = KernelLogLevel::new();

/// 日志级别
#[derive(Default, Clone, PartialEq, Debug)]
pub enum LogLevel {
EMERG = 0,
ALERT = 1,
CRIT = 2,
ERR = 3,
WARN = 4,
NOTICE = 5,
INFO = 6,
DEBUG = 7,
#[default]
DEFAULT = 8,
}

impl From<usize> for LogLevel {
fn from(value: usize) -> Self {
match value {
0 => LogLevel::EMERG,
1 => LogLevel::ALERT,
2 => LogLevel::CRIT,
3 => LogLevel::ERR,
4 => LogLevel::WARN,
5 => LogLevel::NOTICE,
6 => LogLevel::INFO,
7 => LogLevel::DEBUG,
_ => LogLevel::DEFAULT,
}
}
}

impl From<::log::Level> for LogLevel {
fn from(value: ::log::Level) -> Self {
match value {
log::Level::Error => LogLevel::ERR, // 3
log::Level::Warn => LogLevel::WARN, // 4
log::Level::Info => LogLevel::INFO, // 6
log::Level::Debug => LogLevel::DEBUG, // 7
log::Level::Trace => LogLevel::DEBUG, // 7 (maps to DEBUG)
}
}
}

/// 内核日志级别管理结构
#[derive(Debug)]
pub struct KernelLogLevel {
/// 控制台输出级别 (console_loglevel)
/// 只有级别小于等于此值的消息才会输出到控制台
pub console_level: AtomicU8,
/// 默认消息级别 (default_message_loglevel)
pub default_message_level: AtomicU8,
/// 最小控制台级别 (minimum_console_loglevel)
pub minimum_level: AtomicU8,
/// 默认控制台级别 (default_console_loglevel)
pub default_console_level: AtomicU8,
}

impl KernelLogLevel {
/// 创建新的内核日志级别配置
///
/// 默认值遵循Linux内核标准:
/// - console_loglevel: 7 (DEBUG)
/// - default_message_loglevel: 4 (WARNING)
/// - minimum_console_loglevel: 1 (ALERT)
/// - default_console_loglevel: 7 (DEBUG)
pub const fn new() -> Self {
Self {
console_level: AtomicU8::new(7), // DEBUG级别
default_message_level: AtomicU8::new(4), // WARNING级别
minimum_level: AtomicU8::new(1), // ALERT级别
default_console_level: AtomicU8::new(7), // DEBUG级别
}
}

/// 检查消息是否应该被输出到控制台
///
/// # 参数
/// - `message_level`: 消息级别 (0-7)
///
/// # 返回值
/// - `true`: 消息级别 <= 控制台级别,应该输出
/// - `false`: 消息级别 > 控制台级别,应该过滤
///
/// # Linux语义
/// 遵循Linux内核的过滤规则:message_level <= console_loglevel
pub fn should_print(&self, message_level: LogLevel) -> bool {
let console_level = self.console_level.load(Ordering::Acquire);
// Linux语义:message_level <= console_loglevel 时输出
message_level as u8 <= console_level
}

/// 设置控制台日志级别
///
/// # 参数
/// - `level`: 新的控制台级别 (0-7)
///
/// # 返回值
/// - `Ok(())`: 设置成功
/// - `Err(SystemError::EINVAL)`: 级别值无效
pub fn set_console_level(&self, level: u8) -> Result<(), SystemError> {
if level <= 7 {
self.console_level.store(level, Ordering::Release);
Ok(())
} else {
Err(SystemError::EINVAL)
}
}

/// 获取当前控制台日志级别
pub fn get_console_level(&self) -> u8 {
self.console_level.load(Ordering::Acquire)
}

/// 获取默认消息级别
pub fn get_default_message_level(&self) -> u8 {
self.default_message_level.load(Ordering::Acquire)
}

/// 获取最小控制台级别
pub fn get_minimum_level(&self) -> u8 {
self.minimum_level.load(Ordering::Acquire)
}

/// 获取默认控制台级别
pub fn get_default_console_level(&self) -> u8 {
self.default_console_level.load(Ordering::Acquire)
}

/// 获取所有日志级别配置
///
/// # 返回值
/// 返回包含四个级别值的数组:[console, default_message, minimum, default_console]
pub fn get_all_levels(&self) -> [u8; 4] {
[
self.get_console_level(),
self.get_default_message_level(),
self.get_minimum_level(),
self.get_default_console_level(),
]
}
}

/// loglevel命令行参数处理
///
/// 支持格式:loglevel=N (N=0-7)
/// 示例:loglevel=4 只输出WARNING及以上级别的日志
#[linkme::distributed_slice(KCMDLINE_PARAM_KV)]
static LOGLEVEL_PARAM: KernelCmdlineParameter = KernelCmdlineParameter::KV(KernelCmdlineKV {
name: "loglevel",
value: None,
initialized: false,
default: "7", // 默认DEBUG级别
});

/// 处理loglevel参数
///
/// 在cmdline参数解析完成后调用,设置全局日志级别
pub fn handle_loglevel_param() {
if let Some(param) = KCMDLINE_PARAM_KV.iter().find(|x| x.name() == "loglevel") {
if let Some(value_str) = param.value_str() {
if let Ok(level) = value_str.parse::<u8>() {
if level <= 7 {
let _ = KERNEL_LOG_LEVEL.set_console_level(level);
log::info!("loglevel: set console log level to {} via cmdline", level);
} else {
log::warn!("loglevel: invalid level {}, must be 0-7", level);
}
} else {
log::warn!("loglevel: invalid value '{}', must be a number", value_str);
}
}
}
}
1 change: 1 addition & 0 deletions kernel/src/debug/klog/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod loglevel;
pub mod mm;
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,7 @@ use core::fmt::{Display, Formatter, Result};

use alloc::string::String;

use crate::time::PosixTimeSpec;

// /// 日志类型
// #[derive(Default, Clone, Debug)]
// pub enum LogType {
// /// 启动信息
// Startup,
// /// 驱动信息
// Driver,
// /// 系统信息
// System,
// /// 硬件信息
// Hardware,
// /// 内核模块信息
// KernelModule,
// /// 内核调试信息
// KernelDebug,
// #[default]
// Default,
// }

/// 日志级别
#[derive(Default, Clone, PartialEq, Debug)]
pub enum LogLevel {
EMERG = 0,
ALERT = 1,
CRIT = 2,
ERR = 3,
WARN = 4,
NOTICE = 5,
INFO = 6,
DEBUG = 7,
#[default]
DEFAULT = 8,
}

impl From<usize> for LogLevel {
fn from(value: usize) -> Self {
match value {
0 => LogLevel::EMERG,
1 => LogLevel::ALERT,
2 => LogLevel::CRIT,
3 => LogLevel::ERR,
4 => LogLevel::WARN,
5 => LogLevel::NOTICE,
6 => LogLevel::INFO,
7 => LogLevel::DEBUG,
_ => LogLevel::DEFAULT,
}
}
}
use crate::{debug::klog::loglevel::LogLevel, time::PosixTimeSpec};

/// 日志消息
#[derive(Default, Clone, Debug)]
Expand Down
6 changes: 3 additions & 3 deletions kernel/src/filesystem/procfs/kmsg.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::sync::atomic::{compiler_fence, Ordering};

use super::log::{LogLevel, LogMessage};
use super::klog::LogMessage;

use crate::libs::spinlock::SpinLock;
use crate::{debug::klog::loglevel::LogLevel, libs::spinlock::SpinLock};

use alloc::{borrow::ToOwned, string::ToString, vec::Vec};

Expand Down Expand Up @@ -52,7 +52,7 @@ impl Kmsg {

/// 添加日志消息
pub fn push(&mut self, msg: LogMessage) {
self.buffer.push(msg);
self.buffer.push(msg.clone());
self.is_changed = true;
}

Expand Down
51 changes: 42 additions & 9 deletions kernel/src/filesystem/procfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ use crate::{
arch::mm::LockedFrameAllocator,
driver::base::device::device_number::DeviceNumber,
filesystem::{
procfs::proc_thread_self_ns::{
current_thread_self_ns_ino, open_thread_self_ns_file, read_thread_self_ns_link,
ThreadSelfNsFileType,
procfs::{
proc_thread_self_ns::{
current_thread_self_ns_ino, open_thread_self_ns_file, read_thread_self_ns_link,
ThreadSelfNsFileType,
},
sys::sysctl::PrintkSysctl,
},
vfs::{
mount::{MountFlags, MountPath},
Expand All @@ -43,13 +46,14 @@ use super::vfs::{
FileSystem, FsInfo, IndexNode, InodeId, Magic, Metadata, SuperBlock,
};

pub mod klog;
pub mod kmsg;
pub mod log;
mod proc_cpuinfo;
mod proc_mounts;
mod proc_thread_self_ns;
mod proc_version;
mod procfs_setup;
mod sys;
mod syscall;

/// @brief 进程文件类型
Expand Down Expand Up @@ -77,6 +81,8 @@ pub enum ProcFileType {
ProcThreadSelfNsRoot,
/// /proc/thread-self/ns/* namespace files
ProcThreadSelfNsChild(ThreadSelfNsFileType),
/// /proc/sys/kernel/printk
ProcSysKernelPrintk,
//todo: 其他文件类型
///默认文件类型
Default,
Expand Down Expand Up @@ -799,7 +805,8 @@ impl IndexNode for LockedProcFSInode {
ProcFileType::ProcKmsg
| ProcFileType::ProcFdDir
| ProcFileType::ProcFdFile
| ProcFileType::ProcThreadSelfNsRoot => 0,
| ProcFileType::ProcThreadSelfNsRoot
| ProcFileType::ProcSysKernelPrintk => 0,
};

// 为不同类型的 procfs 节点设置文件私有数据
Expand Down Expand Up @@ -883,6 +890,12 @@ impl IndexNode for LockedProcFSInode {
return read_thread_self_ns_link(ns_type, buf, offset)
}

ProcFileType::ProcSysKernelPrintk => {
// 使用 PrintkSysctl 处理 /proc/sys/kernel/printk 文件读取
let buflen = buf.len().min(len);
return PrintkSysctl.read_to_buffer(&mut buf[..buflen]);
}

_ => (),
};

Expand All @@ -903,12 +916,32 @@ impl IndexNode for LockedProcFSInode {

fn write_at(
&self,
_offset: usize,
_len: usize,
_buf: &[u8],
offset: usize,
len: usize,
buf: &[u8],
_data: SpinLockGuard<FilePrivateData>,
) -> Result<usize, SystemError> {
return Err(SystemError::ENOSYS);
if offset > 0 {
// 不支持随机写入
return Err(SystemError::EINVAL);
}

let inode = self.0.lock();

// 检查当前inode是否为一个文件夹,如果是的话,就返回错误
if inode.metadata.file_type == FileType::Dir {
return Err(SystemError::EISDIR);
}

// 根据文件类型处理写入
match inode.fdata.ftype {
ProcFileType::ProcSysKernelPrintk => {
// 使用 PrintkSysctl 处理 /proc/sys/kernel/printk 文件写入
let buflen = buf.len().min(len);
return PrintkSysctl.write_from_buffer(&buf[..buflen]);
}
_ => Err(SystemError::ENOSYS),
}
}

fn fs(&self) -> Arc<dyn FileSystem> {
Expand Down
1 change: 1 addition & 0 deletions kernel/src/filesystem/procfs/procfs_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ impl ProcFS {
self.create_version_file();
self.create_cpuinfo_file();
self.create_self_file();
self.create_sysctl_files();
}

/// @brief 创建 /proc/meminfo 文件
Expand Down
Loading