实现内核日志系统 (#489)

* 实现写日志和读取日志,并且能够在用户态下执行dmesg命令查看日志

* 通过klogctl实现dmesg

* 改用ConstGenericRingBuffer作内核缓冲区

* 更改缓冲区容量

* 将能够输出到控制台的日志级别改为日志级别枚举类,使用SpinLock控制KMSG,使用枚举类定义SYSLOG_ACTION,将do_syslog系统调用接口放在syscall.rs

* fix warning

* 完善do_syslog注释

* 将KMSG接入kinfo、kdebug等

* fix warning

* 修复显示的秒数不正确,·以及无法通过CI的问题
This commit is contained in:
Jomo 2024-01-24 16:13:15 +08:00 committed by GitHub
parent d46c6d2794
commit 8d72b68da9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 763 additions and 26 deletions

View File

@ -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

View File

@ -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,12 +40,14 @@ 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

View File

@ -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)

View File

@ -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": "",

View File

@ -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" }

View File

@ -6,4 +6,6 @@ pub extern crate thingbuf;
pub extern crate memoffset;
pub extern crate ringbuffer;
pub extern crate crc;

View File

@ -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()
);
}
}

View File

@ -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() {

View File

@ -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!");
}
}
}

View File

@ -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()
);
}
}

View File

@ -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<SpinLock<Kmsg>> = None;
/// 初始化KMSG
pub fn kmsg_init() {
let kmsg = SpinLock::new(Kmsg::new());
unsafe { KMSG = Some(kmsg) };
}
/// 日志
pub struct Kmsg {
/// 环形缓冲区
buffer: AllocRingBuffer<LogMessage>,
/// 缓冲区字节数组
data: Vec<u8>,
/// 能够输出到控制台的日志级别当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<usize, SystemError> {
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<usize, SystemError> {
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<usize, SystemError> {
let mut data_level: Vec<u8> = 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<usize, SystemError> {
let r = self.read_all(buf);
self.clear()?;
return r;
}
/// 清空缓冲区
pub fn clear(&mut self) -> Result<usize, SystemError> {
self.buffer.clear();
self.data.clear();
return Ok(0);
}
/// 设置输出到控制台的日志级别
pub fn set_level(&mut self, log_level: usize) -> Result<usize, SystemError> {
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<usize, SystemError> {
return Ok(self.tobytes());
}
}

View File

@ -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<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,
}
}
}
/// 日志消息
#[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);
}
}

View File

@ -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<u8> 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::<LockedProcFSInode>()
.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 => (),
};

View File

@ -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<usize> 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<usize, SystemError> {
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),
}
}
}

View File

@ -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()
);
}
}

View File

@ -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) };
}
}
}

View File

@ -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");

View File

@ -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 {

View File

@ -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()
);
}
}

View File

@ -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/"

View File

@ -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

1
user/apps/dmesg/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
dmesg

17
user/apps/dmesg/Makefile Normal file
View File

@ -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

86
user/apps/dmesg/dmesg.c Normal file
View File

@ -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 <list> 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);
}

31
user/apps/dmesg/dmesg.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <string.h>
/**
* @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();

113
user/apps/dmesg/main.c Normal file
View File

@ -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;
}

View File

@ -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": []
}