diff --git a/.github/actions/import-toolchain/action.yml b/.github/actions/import-toolchain/action.yml index fc1eff0b..3938fa86 100644 --- a/.github/actions/import-toolchain/action.yml +++ b/.github/actions/import-toolchain/action.yml @@ -15,7 +15,8 @@ runs: with: path: | ~/opt - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('tools/build_gcc_toolchain.sh') }}-${{ hashFiles('tools/install_musl_gcc.sh') }} + ~/.bashrc + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('tools/build_gcc_toolchain.sh') }} - name: Cache build tools id: cache-build-tools @@ -28,7 +29,8 @@ runs: ~/.cargo ~/.rustup ~/.bashrc - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.dadk_version }}-${{ hashFiles('.github/workflows/cache-toolchain.yml') }} + ~/opt + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.dadk_version }}-${{ hashFiles('.github/workflows/cache-toolchain.yml') }}-${{ hashFiles('tools/install_musl_gcc.sh') }} - uses: ./.github/actions/install-apt-packages diff --git a/.github/workflows/cache-toolchain.yml b/.github/workflows/cache-toolchain.yml index f5245918..8c35039a 100644 --- a/.github/workflows/cache-toolchain.yml +++ b/.github/workflows/cache-toolchain.yml @@ -18,14 +18,14 @@ jobs: with: path: | ~/opt - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('tools/build_gcc_toolchain.sh') }}-${{ hashFiles('tools/install_musl_gcc.sh') }} + ~/.bashrc + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('tools/build_gcc_toolchain.sh') }} - if: ${{ steps.cache-dragonos-gcc.outputs.cache-hit != 'true' }} name: build dragonos-gcc continue-on-error: true run: | bash tools/build_gcc_toolchain.sh -f - bash tools/install_musl_gcc.sh - uses: ./.github/actions/install-apt-packages @@ -40,13 +40,15 @@ jobs: ~/.cargo ~/.rustup ~/.bashrc - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.dadk_version }}-${{ hashFiles('.github/workflows/cache-toolchain.yml') }} + ~/opt + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.dadk_version }}-${{ hashFiles('.github/workflows/cache-toolchain.yml') }}-${{ hashFiles('tools/install_musl_gcc.sh') }} - if: ${{ steps.cache-build-tools.outputs.cache-hit != 'true' }} name: Install toolchain continue-on-error: false run: | - + USE_GITHUB=1 bash tools/install_musl_gcc.sh + cargo install cargo-binutils rustup toolchain install nightly-x86_64-unknown-linux-gnu rustup toolchain install nightly-2023-01-21-x86_64-unknown-linux-gnu diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 523b5e91..e6e7102a 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -2,7 +2,7 @@ name: Build Check on: push: - branches: [ "master", "patch-add-riscv64-github-workflow" ] + branches: [ "master" ] pull_request: branches: [ "master" ] @@ -50,6 +50,7 @@ jobs: - uses: ./.github/actions/import-toolchain - name: Run kernel static test + shell: bash -ileo pipefail {0} env: ARCH: ${{ matrix.arch }} run: bash -c "source ~/.cargo/env && cd kernel && make test" @@ -68,7 +69,14 @@ jobs: - name: build the DragonOS env: ARCH: x86_64 - run: bash -c "source ~/.cargo/env && export DragonOS_GCC=$HOME/opt/dragonos-gcc/gcc-x86_64-unknown-none/bin && make -j $(nproc) " + shell: bash -ileo pipefail {0} + + run: | + source ~/.bashrc + source ~/.cargo/env + export DragonOS_GCC=$HOME/opt/dragonos-gcc/gcc-x86_64-unknown-none/bin + + make -j $(nproc) build-riscv64: @@ -84,8 +92,9 @@ jobs: - uses: ./.github/actions/import-toolchain - name: build the DragonOS + shell: bash -ileo pipefail {0} env: ARCH: riscv64 - run: bash -c "source ~/.cargo/env && make kernel -j $(nproc)" + run: source ~/.bashrc && source ~/.cargo/env && make kernel -j $(nproc) diff --git a/.vscode/settings.json b/.vscode/settings.json index c00fa165..6409ec20 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -172,7 +172,13 @@ "clocksource.h": "c", "ata.h": "c", "barrier": "c", - "charconv": "c" + "charconv": "c", + "printf.h": "c", + "klog.h": "c", + "sqlite3ext.h": "c", + "malloc.h": "c", + "*.o": "c", + "k_log.h": "c" }, "C_Cpp.errorSquiggles": "enabled", "esbonio.sphinx.confDir": "", diff --git a/kernel/crates/kdepends/Cargo.toml b/kernel/crates/kdepends/Cargo.toml index cde833db..5f4931d9 100644 --- a/kernel/crates/kdepends/Cargo.toml +++ b/kernel/crates/kdepends/Cargo.toml @@ -7,6 +7,7 @@ description = "需要导出的依赖项(为保持内核依赖版本与调试 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ringbuffer = "0.15.0" memoffset = "0.9.0" crc = { path = "../crc" } diff --git a/kernel/crates/kdepends/src/lib.rs b/kernel/crates/kdepends/src/lib.rs index 6129ec46..363d999b 100644 --- a/kernel/crates/kdepends/src/lib.rs +++ b/kernel/crates/kdepends/src/lib.rs @@ -6,4 +6,6 @@ pub extern crate thingbuf; pub extern crate memoffset; +pub extern crate ringbuffer; + pub extern crate crc; diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 3281c3bc..d798ec1c 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -491,7 +491,7 @@ impl SignalArch for X86_64SignalArch { "Error occurred when handling signal: {}, pid={:?}, errcode={:?}", sig_number as i32, ProcessManager::current_pcb().pid(), - res.unwrap_err() + res.as_ref().unwrap_err() ); } } diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 618a0d34..06afe3f1 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -8,6 +8,7 @@ use x86::time::rdtsc; use x86_64::registers::model_specific::EferFlags; use crate::driver::tty::serial::serial8250::send_to_default_serial8250_port; +use crate::filesystem::procfs::kmsg::kmsg_init; use crate::include::bindings::bindings::{ multiboot2_get_load_base, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t, multiboot_tag_load_base_addr_t, @@ -419,6 +420,8 @@ pub fn mm_init() { unsafe { allocator_init() }; // enable mmio mmio_init(); + // enable KMSG + kmsg_init(); } unsafe fn allocator_init() { diff --git a/kernel/src/driver/net/e1000e/e1000e.rs b/kernel/src/driver/net/e1000e/e1000e.rs index 05dc4dfe..9d061df4 100644 --- a/kernel/src/driver/net/e1000e/e1000e.rs +++ b/kernel/src/driver/net/e1000e/e1000e.rs @@ -594,8 +594,12 @@ pub extern "C" fn rs_e1000e_init() { pub fn e1000e_init() -> () { match e1000e_probe() { - Ok(_code) => kinfo!("Successfully init e1000e device!"), - Err(_error) => kinfo!("Error occurred!"), + Ok(_code) => { + kinfo!("Successfully init e1000e device!"); + } + Err(_error) => { + kinfo!("Error occurred!"); + } } } diff --git a/kernel/src/filesystem/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs index f7c1065c..87e6fa78 100644 --- a/kernel/src/filesystem/fat/fs.rs +++ b/kernel/src/filesystem/fat/fs.rs @@ -1196,7 +1196,7 @@ impl Drop for FATFileSystem { if r.is_err() { kerror!( "Umount FAT filesystem failed: errno={:?}, FS detail:{self:?}", - r.unwrap_err() + r.as_ref().unwrap_err() ); } } diff --git a/kernel/src/filesystem/procfs/kmsg.rs b/kernel/src/filesystem/procfs/kmsg.rs new file mode 100644 index 00000000..fe8101db --- /dev/null +++ b/kernel/src/filesystem/procfs/kmsg.rs @@ -0,0 +1,151 @@ +use super::log::{LogLevel, LogMessage}; + +use crate::libs::spinlock::SpinLock; + +use alloc::{borrow::ToOwned, string::ToString, vec::Vec}; + +use kdepends::ringbuffer::{AllocRingBuffer, RingBuffer}; + +use system_error::SystemError; + +/// 缓冲区容量 +const KMSG_BUFFER_CAPACITY: usize = 1024; + +/// 全局环形缓冲区 +pub static mut KMSG: Option> = None; + +/// 初始化KMSG +pub fn kmsg_init() { + let kmsg = SpinLock::new(Kmsg::new()); + unsafe { KMSG = Some(kmsg) }; +} + +/// 日志 +pub struct Kmsg { + /// 环形缓冲区 + buffer: AllocRingBuffer, + /// 缓冲区字节数组 + data: Vec, + /// 能够输出到控制台的日志级别,当console_loglevel为DEFAULT时,表示可以打印所有级别的日志消息到控制台 + console_loglevel: LogLevel, + /// 判断buffer在上一次转成字节数组之后是否发生变动 + is_changed: bool, +} + +impl Kmsg { + pub fn new() -> Self { + Kmsg { + buffer: AllocRingBuffer::new(KMSG_BUFFER_CAPACITY), + data: Vec::new(), + console_loglevel: LogLevel::DEFAULT, + is_changed: false, + } + } + + /// 添加日志消息 + pub fn push(&mut self, msg: LogMessage) { + self.buffer.push(msg); + self.is_changed = true; + } + + /// 读取缓冲区 + pub fn read(&mut self, buf: &mut [u8]) -> Result { + self.tobytes(); + + match self.console_loglevel { + LogLevel::DEFAULT => self.read_all(buf), + _ => self.read_level(buf), + } + } + + /// 读取缓冲区所有日志消息 + fn read_all(&mut self, buf: &mut [u8]) -> Result { + let len = self.data.len().min(buf.len()); + + // 拷贝数据 + let src = &self.data[0..len]; + buf[0..src.len()].copy_from_slice(src); + + return Ok(src.len()); + } + + /// 读取缓冲区特定level的日志消息 + fn read_level(&mut self, buf: &mut [u8]) -> Result { + let mut data_level: Vec = Vec::new(); + + for msg in self.buffer.iter() { + if msg.level() == self.console_loglevel { + data_level.append(&mut msg.to_string().as_bytes().to_owned()); + } + } + + let len = data_level.len().min(buf.len()); + + // 拷贝数据 + let src = &data_level[0..len]; + buf[0..src.len()].copy_from_slice(src); + + // 将控制台输出日志level改回默认,否则之后都是打印特定level的日志消息 + self.console_loglevel = LogLevel::DEFAULT; + + return Ok(data_level.len()); + } + + /// 读取并清空缓冲区 + pub fn read_clear(&mut self, buf: &mut [u8]) -> Result { + let r = self.read_all(buf); + self.clear()?; + + return r; + } + + /// 清空缓冲区 + pub fn clear(&mut self) -> Result { + self.buffer.clear(); + self.data.clear(); + + return Ok(0); + } + + /// 设置输出到控制台的日志级别 + pub fn set_level(&mut self, log_level: usize) -> Result { + let log_level = log_level - 1; + + self.console_loglevel = match log_level { + 0 => LogLevel::EMERG, + 1 => LogLevel::ALERT, + 2 => LogLevel::CRIT, + 3 => LogLevel::ERR, + 4 => LogLevel::WARN, + 5 => LogLevel::NOTICE, + 6 => LogLevel::INFO, + 7 => LogLevel::DEBUG, + 8 => LogLevel::DEFAULT, + _ => return Err(SystemError::EINVAL), + }; + + return Ok(0); + } + + /// 将环形缓冲区的日志消息转成字节数组以拷入用户buf + fn tobytes(&mut self) -> usize { + if self.is_changed { + self.data.clear(); + + if self.console_loglevel == LogLevel::DEFAULT { + for msg in self.buffer.iter() { + self.data.append(&mut msg.to_string().as_bytes().to_owned()); + } + } + + self.is_changed = false; + } + + return self.data.len(); + } + + // 返回内核缓冲区所占字节数 + pub fn data_size(&mut self) -> Result { + return Ok(self.tobytes()); + } +} diff --git a/kernel/src/filesystem/procfs/log.rs b/kernel/src/filesystem/procfs/log.rs new file mode 100644 index 00000000..06fd2655 --- /dev/null +++ b/kernel/src/filesystem/procfs/log.rs @@ -0,0 +1,107 @@ +use core::fmt::{Display, Formatter, Result}; + +use alloc::string::String; + +use crate::time::TimeSpec; + +// /// 日志类型 +// #[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 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, + } + } +} + +/// 日志消息 +#[derive(Default, Clone, Debug)] +pub struct LogMessage { + /// 时间戳 + timestamp: TimeSpec, + /// 日志级别 + level: LogLevel, + // /// 日志类型 + // log_type: LogType, + /// 日志消息 + message: String, +} + +impl LogMessage { + pub fn new(timestamp: TimeSpec, level: LogLevel, message: String) -> Self { + LogMessage { + timestamp, + level, + message, + } + } + + pub fn level(&self) -> LogLevel { + self.level.clone() + } +} + +impl Display for LogMessage { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let timestamp = &self.timestamp; + let level = match self.level { + LogLevel::EMERG => "EMERG", + LogLevel::ALERT => "ALERT", + LogLevel::CRIT => "CRIT", + LogLevel::ERR => "ERR", + LogLevel::WARN => "WARNING", + LogLevel::NOTICE => "NOTICE", + LogLevel::INFO => "INFO", + LogLevel::DEBUG => "DEBUG", + LogLevel::DEFAULT => "Default", + }; + + let message = &self.message; + + let res = format!( + "<{}>[{}.{}] : {}\n", + level, timestamp.tv_sec, timestamp.tv_nsec, message + ); + return write!(f, "{}", res); + } +} diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index bea3a571..418f52e5 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -33,6 +33,10 @@ use super::vfs::{ FileSystem, FsInfo, IndexNode, InodeId, Metadata, }; +pub mod kmsg; +pub mod log; +mod syscall; + /// @brief 进程文件类型 /// @usage 用于定义进程文件夹下的各类文件类型 #[derive(Debug)] @@ -42,6 +46,8 @@ pub enum ProcFileType { ProcStatus = 0, /// meminfo ProcMeminfo = 1, + /// kmsg + ProcKmsg = 2, //todo: 其他文件类型 ///默认文件类型 Default, @@ -52,6 +58,7 @@ impl From for ProcFileType { match value { 0 => ProcFileType::ProcStatus, 1 => ProcFileType::ProcMeminfo, + 2 => ProcFileType::ProcKmsg, _ => ProcFileType::Default, } } @@ -336,6 +343,19 @@ impl ProcFS { panic!("create meminfo error"); } + // 创建kmsg文件 + let binding = inode.create("kmsg", FileType::File, ModeType::from_bits_truncate(0o444)); + if let Ok(kmsg) = binding { + let kmsg_file = kmsg + .as_any_ref() + .downcast_ref::() + .unwrap(); + kmsg_file.0.lock().fdata.pid = Pid::new(1); + kmsg_file.0.lock().fdata.ftype = ProcFileType::ProcKmsg; + } else { + panic!("create ksmg error"); + } + return result; } @@ -456,6 +476,7 @@ impl IndexNode for LockedProcFSInode { match inode.fdata.ftype { ProcFileType::ProcStatus => return inode.proc_read(offset, len, buf, private_data), ProcFileType::ProcMeminfo => return inode.proc_read(offset, len, buf, private_data), + ProcFileType::ProcKmsg => (), ProcFileType::Default => (), }; diff --git a/kernel/src/filesystem/procfs/syscall.rs b/kernel/src/filesystem/procfs/syscall.rs new file mode 100644 index 00000000..b2e55b6e --- /dev/null +++ b/kernel/src/filesystem/procfs/syscall.rs @@ -0,0 +1,77 @@ +use core::usize; + +use system_error::SystemError; + +use crate::syscall::Syscall; + +use super::kmsg::KMSG; + +/// 操作内核环形缓冲区 +enum SyslogAction { + /// Close the log. Currently a NOP. + SyslogActionClose = 0, + /// Open the log. Currently a NOP. + SyslogActionOpen = 1, + /// Read from the log. + SyslogActionRead = 2, + /// Read and clear all messages remaining in the ring buffer. + SyslogActionReadClear = 4, + /// Clear ring buffer. + SyslogActionClear = 5, + /// Set level of messages printed to console. + SyslogActionConsoleLevel = 8, + /// Return size of the log buffer. + SyslogActionSizeBuffer = 10, + /// Invalid SyslogAction + SyslogActionInval, +} + +impl From for SyslogAction { + fn from(value: usize) -> Self { + match value { + 0 => SyslogAction::SyslogActionClose, + 1 => SyslogAction::SyslogActionOpen, + 2 => SyslogAction::SyslogActionRead, + 4 => SyslogAction::SyslogActionReadClear, + 5 => SyslogAction::SyslogActionClear, + 8 => SyslogAction::SyslogActionConsoleLevel, + 10 => SyslogAction::SyslogActionSizeBuffer, + _ => SyslogAction::SyslogActionInval, + } + } +} + +impl Syscall { + /// # 操作内核环形缓冲区 + /// + /// ## 参数 + /// - syslog_action_type: 操作码 + /// - buf:用户缓冲区 + /// - len: 需要从内核环形缓冲区读取的字节数。如果操作码为8,即SyslogActionConsoleLevel,则len为待设置的日志级别 + /// + /// ## 返回值 + /// - 成功,Ok(usize) + /// - 失败,Err(SystemError) 操作失败,返回posix错误码 + /// + + pub fn do_syslog( + syslog_action_type: usize, + buf: &mut [u8], + len: usize, + ) -> Result { + let syslog_action = SyslogAction::from(syslog_action_type); + + let mut kmsg_guard = unsafe { KMSG.as_ref().unwrap().lock_irqsave() }; + + match syslog_action { + SyslogAction::SyslogActionClose => Ok(0), + SyslogAction::SyslogActionOpen => Ok(0), + SyslogAction::SyslogActionRead => kmsg_guard.read(buf), + SyslogAction::SyslogActionReadClear => kmsg_guard.read_clear(buf), + SyslogAction::SyslogActionClear => kmsg_guard.clear(), + SyslogAction::SyslogActionSizeBuffer => kmsg_guard.data_size(), + SyslogAction::SyslogActionConsoleLevel => kmsg_guard.set_level(len), + SyslogAction::SyslogActionInval => return Err(SystemError::EINVAL), + } + } +} diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index b91c1b60..db89ddd7 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -462,7 +462,7 @@ impl Drop for File { "pid: {:?} failed to close file: {:?}, errno={:?}", ProcessManager::current_pcb().pid(), self, - r.unwrap_err() + r.as_ref().unwrap_err() ); } } diff --git a/kernel/src/libs/printk.rs b/kernel/src/libs/printk.rs index 082cc8f0..138dc10c 100644 --- a/kernel/src/libs/printk.rs +++ b/kernel/src/libs/printk.rs @@ -1,7 +1,17 @@ use core::fmt::{self, Write}; +use alloc::string::ToString; + use super::lib_ui::textui::{textui_putstr, FontColor}; +use crate::{ + filesystem::procfs::{ + kmsg::KMSG, + log::{LogLevel, LogMessage}, + }, + time::TimeSpec, +}; + #[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::libs::printk::__printk(format_args!($($arg)*))); @@ -30,14 +40,15 @@ macro_rules! printk_color { #[macro_export] macro_rules! kdebug { ($($arg:tt)*) => { + $crate::libs::printk::Logger.log(7,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("[ DEBUG ] ({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))) - } } #[macro_export] macro_rules! kinfo { ($($arg:tt)*) => { + $crate::libs::printk::Logger.log(6,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("[ INFO ] ({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))) } } @@ -45,6 +56,7 @@ macro_rules! kinfo { #[macro_export] macro_rules! kwarn { ($($arg:tt)*) => { + $crate::libs::printk::Logger.log(4,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::YELLOW, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ WARN ] "); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); } @@ -53,6 +65,7 @@ macro_rules! kwarn { #[macro_export] macro_rules! kerror { ($($arg:tt)*) => { + $crate::libs::printk::Logger.log(3,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ ERROR ] "); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); } @@ -61,6 +74,7 @@ macro_rules! kerror { #[macro_export] macro_rules! kBUG { ($($arg:tt)*) => { + $crate::libs::printk::Logger.log(1,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ BUG ] "); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); } @@ -97,3 +111,17 @@ impl fmt::Write for PrintkWriter { pub fn __printk(args: fmt::Arguments) { PrintkWriter.write_fmt(args).unwrap(); } + +pub struct Logger; + +impl Logger { + pub fn log(&self, log_level: usize, message: fmt::Arguments) { + if unsafe { !KMSG.is_none() } { + let timestamp: TimeSpec = TimeSpec::now(); + let log_level = LogLevel::from(log_level.clone()); + let log_message = LogMessage::new(timestamp, log_level, message.to_string()); + + unsafe { KMSG.as_ref().unwrap().lock_irqsave().push(log_message) }; + } + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index abd01953..7292e56b 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -853,10 +853,20 @@ impl Syscall { } SYS_GETTID => Self::gettid().map(|tid| tid.into()), SYS_GETUID => Self::getuid().map(|uid| uid.into()), + SYS_SYSLOG => { - kwarn!("SYS_SYSLOG has not yet been implemented"); - Ok(0) + let syslog_action_type = args[0] as usize; + let buf_vaddr = args[1]; + let len = args[2]; + let from_user = frame.from_user(); + let mut user_buffer_writer = + UserBufferWriter::new(buf_vaddr as *mut u8, len, from_user)?; + + let user_buf = user_buffer_writer.buffer(0)?; + let res = Self::do_syslog(syslog_action_type, user_buf, len); + res } + SYS_GETGID => Self::getgid().map(|gid| gid.into()), SYS_SETUID => { kwarn!("SYS_SETUID has not yet been implemented"); diff --git a/kernel/src/time/mod.rs b/kernel/src/time/mod.rs index 2a119ef2..8d20c800 100644 --- a/kernel/src/time/mod.rs +++ b/kernel/src/time/mod.rs @@ -1,8 +1,11 @@ use core::{ fmt, + intrinsics::unlikely, ops::{self, Sub}, }; +use crate::arch::CurrentTimeArch; + use self::timekeep::ktime_get_real_ns; pub mod clocksource; @@ -55,6 +58,27 @@ impl TimeSpec { tv_nsec: nsec, }; } + + /// 获取当前时间 + pub fn now() -> Self { + #[cfg(target_arch = "x86_64")] + { + use crate::arch::driver::tsc::TSCManager; + let khz = TSCManager::cpu_khz(); + if unlikely(khz == 0) { + return TimeSpec::default(); + } else { + return Self::from(Duration::from_millis( + CurrentTimeArch::get_cycles() as u64 / khz, + )); + } + } + + #[cfg(target_arch = "riscv64")] + { + unimplemented!("TimeSpec::now()") + } + } } impl Sub for TimeSpec { diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 5a40585b..26c568a6 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -129,7 +129,7 @@ impl Timer { if unlikely(r.is_err()) { kerror!( "Failed to run timer function: {self:?} {:?}", - r.err().unwrap() + r.as_ref().err().unwrap() ); } } diff --git a/tools/install_musl_gcc.sh b/tools/install_musl_gcc.sh index 85d4a1b5..bcf1862a 100644 --- a/tools/install_musl_gcc.sh +++ b/tools/install_musl_gcc.sh @@ -3,12 +3,32 @@ # 该脚本会自动下载musl交叉编译工具链,并将其添加到PATH中 ######################################################################### +export USE_GITHUB=${USE_GITHUB:=0} + + + MUSL_GCC_DATE="231114" MUSL_GCC_VERSION="9.4.0" -MUSL_GCC_X86_64_TAR="x86_64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}.tar.xz" -MUSL_GCC_RISCV64_TAR="riscv64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}.tar.xz" -MUSL_GCC_X86_64_DOWNLOAD_URL="https://mirrors.dragonos.org.cn/pub/third_party/toolchain/gcc/${MUSL_GCC_X86_64_TAR}" -MUSL_GCC_RISCV64_DOWNLOAD_URL="https://mirrors.dragonos.org.cn/pub/third_party/toolchain/gcc/${MUSL_GCC_RISCV64_TAR}" +MUSL_GCC_X86_64_TAR= +MUSL_GCC_RISCV64_TAR= + +MUSL_GCC_X86_64_DOWNLOAD_URL="" +MUSL_GCC_RISCV64_DOWNLOAD_URL="" +if [ $USE_GITHUB -eq 1 ]; then + echo "Download from github" + + MUSL_GCC_X86_64_TAR=x86_64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}.tar.xz + MUSL_GCC_RISCV64_TAR=riscv64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}.tar.xz + MUSL_GCC_X86_64_DOWNLOAD_URL="https://github.com/DragonOS-Community/musl-cross-make/releases/download/${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}/${MUSL_GCC_X86_64_TAR}" + MUSL_GCC_RISCV64_DOWNLOAD_URL="https://github.com/DragonOS-Community/musl-cross-make/releases/download/${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}/${MUSL_GCC_RISCV64_TAR}" + https://github.com/DragonOS-Community/musl-cross-make/releases/download/9.4.0-231114/riscv64-linux-musl-cross-gcc-9.4.0.tar.xz +else + echo "Download from mirrors.dragonos.org.cn" + MUSL_GCC_X86_64_TAR="x86_64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}.tar.xz" + MUSL_GCC_RISCV64_TAR="riscv64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}.tar.xz" + MUSL_GCC_X86_64_DOWNLOAD_URL="https://mirrors.dragonos.org.cn/pub/third_party/toolchain/gcc/${MUSL_GCC_X86_64_TAR}" + MUSL_GCC_RISCV64_DOWNLOAD_URL="https://mirrors.dragonos.org.cn/pub/third_party/toolchain/gcc/${MUSL_GCC_RISCV64_TAR}" +fi INSTALL_POS="$HOME/opt/" diff --git a/user/Makefile b/user/Makefile index 8f6ee75d..c2f58ed0 100644 --- a/user/Makefile +++ b/user/Makefile @@ -51,9 +51,8 @@ endif .PHONY: dadk_run dadk_run: install_dadk mkdir -p $(DADK_CACHE_DIR) -# 之所以在这里临时设置ARCH为空,是因为如果要设置这个环境变量,应当在DADK的配置文件中设置 - ARCH= dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot build - ARCH= dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot install + dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot build + dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot install .PHONY: dadk_clean dadk_clean: install_dadk diff --git a/user/apps/dmesg/.gitignore b/user/apps/dmesg/.gitignore new file mode 100644 index 00000000..6bd031b7 --- /dev/null +++ b/user/apps/dmesg/.gitignore @@ -0,0 +1 @@ +dmesg diff --git a/user/apps/dmesg/Makefile b/user/apps/dmesg/Makefile new file mode 100644 index 00000000..0bca7f4b --- /dev/null +++ b/user/apps/dmesg/Makefile @@ -0,0 +1,17 @@ +ifeq ($(ARCH), x86_64) +export PREFIX=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) +export PREFIX=riscv64-linux-musl- +endif + + +export CC=$(PREFIX)gcc + +all: dmesg + mv dmesg $(DADK_CURRENT_BUILD_DIR) + +dmesg: main.c + $(CC) -static -o dmesg main.c dmesg.c + +clean: + rm dmesg *.o \ No newline at end of file diff --git a/user/apps/dmesg/dmesg.c b/user/apps/dmesg/dmesg.c new file mode 100644 index 00000000..71ed5950 --- /dev/null +++ b/user/apps/dmesg/dmesg.c @@ -0,0 +1,86 @@ +#include "dmesg.h" + +/** + * @brief 识别dmesg程序的第一个选项参数 + * + * @param arg dmesg命令第一个选项参数 + * @return int 有效时返回对应选项码,无效时返回 -1 + */ +int getopt(char *arg) +{ + if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) + return 0; + else if (!strcmp(arg, "-c") || !strcmp(arg, "--read-clear")) + return 4; + else if (!strcmp(arg, "-C") || !strcmp(arg, "--clear")) + return 5; + else if (!strcmp(arg, "-l") || !strcmp(arg, "--level")) + return 8; + + return -1; +} + +/** + * @brief 识别dmesg程序的第二个选项参数 + * + * @param arg dmesg命令第一个选项参数 + * @return int 有效时返回设置的日志级别,无效时返回 -1 + */ +int getlevel(char *arg) +{ + if (!strcmp(arg, "EMERG") || !strcmp(arg, "emerg")) + return 0; + else if (!strcmp(arg, "ALERT") || !strcmp(arg, "alert")) + return 1; + else if (!strcmp(arg, "CRIT") || !strcmp(arg, "crit")) + return 2; + else if (!strcmp(arg, "ERR") || !strcmp(arg, "err")) + return 3; + else if (!strcmp(arg, "WARN") || !strcmp(arg, "warn")) + return 4; + else if (!strcmp(arg, "NOTICE") || !strcmp(arg, "notice")) + return 5; + else if (!strcmp(arg, "INFO") || !strcmp(arg, "info")) + return 6; + else if (!strcmp(arg, "DEBUG") || !strcmp(arg, "debug")) + return 7; + else + { + printf("dmesg: unknown level '%s'\n", arg); + } + return -2; +} + +/** + * @brief 打印dmesg手册 + */ +void print_help_msg() +{ + const char *help_msg = "Usage:\n" + " dmesg [options]\n\n" + "Display or control the kernel ring buffer.\n\n" + "Options:\n" + " -C, --clear clear the kernel ring buffer\n" + " -c, --read-clear read and clear all messages\n" + " -l, --level restrict output to defined levels\n" + " -h, --help display this help\n\n" + "Supported log levels (priorities):\n" + " emerg - system is unusable\n" + " alert - action must be taken immediately\n" + " crit - critical conditions\n" + " err - error conditions\n" + " warn - warning conditions\n" + " notice - normal but significant condition\n" + " info - informational\n" + " debug - debug-level messages\n"; + printf("%s\n", help_msg); +} + +/** + * @brief 打印dmesg错误使用的信息 + */ +void print_bad_usage_msg() +{ + const char *bad_usage_msg = "dmesg: bad usage\nTry 'dmesg --help' for more information."; + printf("%s\n", bad_usage_msg); +} \ No newline at end of file diff --git a/user/apps/dmesg/dmesg.h b/user/apps/dmesg/dmesg.h new file mode 100644 index 00000000..e2d0fbe9 --- /dev/null +++ b/user/apps/dmesg/dmesg.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +/** + * @brief 识别dmesg程序的第一个选项参数 + * + * @param arg dmesg命令第一个选项参数 + * @return int 有效时返回对应选项码,无效时返回 -1 + */ +int getopt(char *arg); + +/** + * @brief 识别dmesg程序的第二个选项参数 + * + * @param arg dmesg命令第一个选项参数 + * @return int 有效时返回设置的日志级别,无效时返回 -1 + */ +int getlevel(char *arg); + +/** + * @brief 打印dmesg手册 + */ +void print_help_msg(); + +/** + * @brief 打印dmesg错误使用的信息 + */ +void print_bad_usage_msg(); \ No newline at end of file diff --git a/user/apps/dmesg/main.c b/user/apps/dmesg/main.c new file mode 100644 index 00000000..ba479f71 --- /dev/null +++ b/user/apps/dmesg/main.c @@ -0,0 +1,113 @@ +#include "dmesg.h" + +int main(int argc, char **argv) +{ + unsigned int len = 1; + char *buf = NULL; + int opt; + unsigned int color = 65280; + + // 获取内核缓冲区大小 + len = klogctl(10, buf, len); + + if (len < 16 * 1024) + len = 16 * 1024; + if (len > 16 * 1024 * 1024) + len = 16 * 1024 * 1024; + + buf = malloc(len); + if (buf == NULL) + { + perror(""); + return -1; + } + + if (argc == 1) + { + // 无选项参数,默认打印所有日志消息 + len = klogctl(2, buf, len); + } + else + { + // 获取第一个选项参数 + opt = getopt(argv[1]); + + // 无效参数 + if (opt == -1) + { + print_bad_usage_msg(); + return -1; + } + // 打印帮助手册 + else if (opt == 0) + { + print_help_msg(); + return 0; + } + // 4 -> 读取内核缓冲区后,清空缓冲区 + // 5 -> 清空内核缓冲区 + else if (opt == 4 || opt == 5) + { + len = klogctl(opt, buf, len); + } + // 读取特定日志级别的消息 + else if (opt == 8) + { + // 无指定日志级别参数,打印错误使用信息 + if (argc < 3) + { + print_bad_usage_msg(); + return -1; + } + + int level = -1; + + // 获取日志级别 + // 这里加1的原因是:如果klogctl的第三个参数是0,不会发生系统调用 + level = getlevel(argv[2]) + 1; + + if (level == -1) + return -1; + + klogctl(8, buf, level); + len = klogctl(2, buf, len); + } + } + + // 当前打印内容 + // 0: 日志级别 + // 1: 时间戳 + // 2: 代码行号 + // 3: 日志消息 + unsigned int content = 0; + for (int i = 0; i < len; i++) + { + char c[2]; + c[0] = buf[i]; + c[1] = '\0'; + syscall(100000, &c[0], color, 0); + if (content == 0 && buf[i] == '>') + { + content++; + } + else if (content == 1 && buf[i] == ']') + { + color = 16744448; + content++; + } + else if (content == 2 && buf[i] == ')') + { + color = 16777215; + content++; + } + else if (content == 3 && buf[i] == '\n') + { + color = 65280; + content = 0; + } + } + + free(buf); + + return 0; +} \ No newline at end of file diff --git a/user/dadk/config/dmesg-0.1.0.dadk b/user/dadk/config/dmesg-0.1.0.dadk new file mode 100644 index 00000000..2598b886 --- /dev/null +++ b/user/dadk/config/dmesg-0.1.0.dadk @@ -0,0 +1,23 @@ +{ + "name": "dmesg", + "version": "0.1.0", + "description": "查看日志", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/dmesg" + } + } + }, + "depends": [ ], + "build": { + "build_command": "make" + }, + "install": { + "in_dragonos_path": "/bin" + }, + "clean": { + "clean_command": "make clean" + }, + "envs": [] +} \ No newline at end of file