使用rust重构softirq机制;解决Rtc驱动的编译警告问题 (#138)

* 使用rust重构softirq机制
* 解决Rtc驱动的编译警告问题

Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
Gou Ngai
2023-01-07 23:15:37 +08:00
committed by GitHub
parent e9fdc57bf8
commit 62e4613978
10 changed files with 386 additions and 257 deletions

View File

@ -1,4 +1,9 @@
pub struct rtc_time_t {
use crate::{
arch::interrupt::{cli, sti},
include::bindings::bindings::{io_in8, io_out8},
};
pub struct RtcTime {
pub second: i32,
pub minute: i32,
pub hour: i32,
@ -7,10 +12,79 @@ pub struct rtc_time_t {
pub year: i32,
}
use crate::{
arch::interrupt::{cli, sti},
include::bindings::bindings::{io_in8, io_out8},
};
impl Default for RtcTime {
fn default() -> Self {
Self {
second: (0),
minute: (0),
hour: (0),
day: (0),
month: (0),
year: (0),
}
}
}
impl RtcTime {
///@brief 从主板cmos中获取时间
///
///@param self time结构体
///@return int 成功则为0
pub fn get(&mut self) -> Result<i32, i32> {
// 为防止中断请求打断该过程,需要先关中断
cli();
//0x0B
let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B
let is_24h: bool = if (status_register_b & 0x02) != 0 {
true
} else {
false
}; // 判断是否启用24小时模式
let is_binary: bool = if (status_register_b & 0x04) != 0 {
true
} else {
false
}; // 判断是否为二进制码
loop {
self.year = read_cmos(CMOSTimeSelector::Year as u8) as i32;
self.month = read_cmos(CMOSTimeSelector::Month as u8) as i32;
self.day = read_cmos(CMOSTimeSelector::Day as u8) as i32;
self.hour = read_cmos(CMOSTimeSelector::Hour as u8) as i32;
self.minute = read_cmos(CMOSTimeSelector::Minute as u8) as i32;
self.second = read_cmos(CMOSTimeSelector::Second as u8) as i32;
if self.second == read_cmos(CMOSTimeSelector::Second as u8) as i32 {
break;
} // 若读取时间过程中时间发生跳变则重新读取
}
unsafe {
io_out8(0x70, 0x00);
}
if !is_binary
// 把BCD转为二进制
{
self.second = (self.second & 0xf) + (self.second >> 4) * 10;
self.minute = (self.minute & 0xf) + (self.minute >> 4) * 10;
self.hour = ((self.hour & 0xf) + ((self.hour & 0x70) >> 4) * 10) | (self.hour & 0x80);
self.day = (self.day & 0xf) + ((self.day / 16) * 10);
self.month = (self.month & 0xf) + (self.month >> 4) * 10;
self.year = (self.year & 0xf) + (self.year >> 4) * 10;
}
self.year += 2000;
if (!is_24h) && (self.hour & 0x80) != 0 {
self.hour = ((self.hour & 0x7f) + 12) % 24;
} // 将十二小时制转为24小时
sti();
return Ok(0);
}
}
///置位0x70的第7位禁止不可屏蔽中断
#[inline]
@ -21,69 +95,13 @@ fn read_cmos(addr: u8) -> u8 {
}
}
/// used in the form of u8
#[repr(u8)]
enum CMOSTimeSelector {
T_SECOND = 0x00,
T_MINUTE = 0x02,
T_HOUR = 0x04,
T_DAY = 0x07,
T_MONTH = 0x08,
T_YEAR = 0x09,
}
///@brief 从主板cmos中获取时间
///
///@param t time结构体
///@return int 成功则为0
pub fn rtc_get_cmos_time(t: &mut rtc_time_t) -> Result<i32,i32> {
unsafe {
// 为防止中断请求打断该过程,需要先关中断
cli();
//0x0B
let status_register_B: u8 = read_cmos(0x0B); // 读取状态寄存器B
let is_24h: bool = if (status_register_B & 0x02) != 0 {
true
} else {
false
}; // 判断是否启用24小时模式
let is_binary: bool = if (status_register_B & 0x04) != 0 {
true
} else {
false
}; // 判断是否为二进制码
loop {
t.year = read_cmos(CMOSTimeSelector::T_YEAR as u8) as i32;
t.month = read_cmos(CMOSTimeSelector::T_MONTH as u8) as i32;
t.day = read_cmos(CMOSTimeSelector::T_DAY as u8) as i32;
t.hour = read_cmos(CMOSTimeSelector::T_HOUR as u8) as i32;
t.minute = read_cmos(CMOSTimeSelector::T_MINUTE as u8) as i32;
t.second = read_cmos(CMOSTimeSelector::T_SECOND as u8) as i32;
if t.second == read_cmos(CMOSTimeSelector::T_SECOND as u8) as i32 {
break;
} // 若读取时间过程中时间发生跳变则重新读取
}
io_out8(0x70, 0x00);
if !is_binary
// 把BCD转为二进制
{
t.second = (t.second & 0xf) + (t.second >> 4) * 10;
t.minute = (t.minute & 0xf) + (t.minute >> 4) * 10;
t.hour = ((t.hour & 0xf) + ((t.hour & 0x70) >> 4) * 10) | (t.hour & 0x80);
t.day = (t.day & 0xf) + ((t.day / 16) * 10);
t.month = (t.month & 0xf) + (t.month >> 4) * 10;
t.year = (t.year & 0xf) + (t.year >> 4) * 10;
}
t.year += 2000;
if (!is_24h) && (t.hour & 0x80) != 0 {
t.hour = ((t.hour & 0x7f) + 12) % 24;
} // 将十二小时制转为24小时
sti();
}
return Ok(0);
Second = 0x00,
Minute = 0x02,
Hour = 0x04,
Day = 0x07,
Month = 0x08,
Year = 0x09,
}

View File

@ -2,7 +2,7 @@
CFLAGS += -I .
all: entry.o irq.o softirq.o trap.o
all: entry.o irq.o trap.o
entry.o: entry.S
$(CC) -E entry.S > _entry.s
@ -11,8 +11,5 @@ entry.o: entry.S
trap.o: trap.c
$(CC) $(CFLAGS) -c trap.c -o trap.o
softirq.o: softirq.c
$(CC) $(CFLAGS) -c softirq.c -o softirq.o
irq.o: irq.c
$(CC) $(CFLAGS) -c irq.c -o irq.o

View File

@ -175,7 +175,6 @@ int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter
p->parameter = paramater;
p->flags = 0;
p->handler = handler;
io_mfence();
p->controller->install(irq_num, arg);
io_mfence();

View File

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

View File

@ -1,120 +0,0 @@
#include "softirq.h"
#include <common/kprint.h>
#include <process/process.h>
#include <driver/video/video.h>
#include <common/spinlock.h>
static struct softirq_t softirq_vector[MAX_SOFTIRQ_NUM] = {0};
static spinlock_t softirq_modify_lock; // 软中断状态status
static volatile uint64_t softirq_pending = 0;
static volatile uint64_t softirq_running = 0;
void set_softirq_pending(uint64_t status)
{
softirq_pending |= status;
}
uint64_t get_softirq_pending()
{
return softirq_pending;
}
#define get_softirq_running() (softirq_running)
/**
* @brief 设置软中断运行结束
*
* @param softirq_num
*/
#define clear_softirq_running(softirq_num) \
do \
{ \
softirq_running &= (~(1 << softirq_num)); \
} while (0)
// 设置软中断的运行状态只应在do_softirq中调用此宏
#define set_softirq_running(softirq_num) \
do \
{ \
softirq_running |= (1 << softirq_num); \
} while (0)
/**
* @brief 清除软中断pending标志位
*
*/
#define softirq_ack(sirq_num) \
do \
{ \
softirq_pending &= (~(1 << sirq_num)); \
} while (0);
/**
* @brief 软中断注册函数
*
* @param irq_num 软中断号
* @param action 响应函数
* @param data 响应数据结构体
*/
void register_softirq(uint32_t irq_num, void (*action)(void *data), void *data)
{
softirq_vector[irq_num].action = action;
softirq_vector[irq_num].data = data;
}
/**
* @brief 卸载软中断
*
* @param irq_num 软中断号
*/
void unregister_softirq(uint32_t irq_num)
{
softirq_vector[irq_num].action = NULL;
softirq_vector[irq_num].data = NULL;
}
/**
* @brief 软中断处理程序
*
*/
void do_softirq()
{
sti();
for (uint32_t i = 0; i < MAX_SOFTIRQ_NUM && softirq_pending; ++i)
{
if (softirq_pending & (1 << i) && softirq_vector[i].action != NULL && (!(get_softirq_running() & (1 << i))))
{
if (spin_trylock(&softirq_modify_lock))
{
// 检测该软中断是否已经被其他进程执行
if(get_softirq_running() & (1 << i))
{
spin_unlock(&softirq_modify_lock);
continue;
}
softirq_ack(i);
set_softirq_running(i);
spin_unlock(&softirq_modify_lock);
softirq_vector[i].action(softirq_vector[i].data);
clear_softirq_running(i);
}
}
}
cli();
}
int clear_softirq_pending(uint32_t irq_num)
{
clear_softirq_running(irq_num);
}
void softirq_init()
{
softirq_pending = 0;
memset(softirq_vector, 0, sizeof(struct softirq_t) * MAX_SOFTIRQ_NUM);
spin_init(&softirq_modify_lock);
}

View File

@ -12,51 +12,16 @@
#include <common/glib.h>
#define MAX_SOFTIRQ_NUM 64
// ==================implementation with rust===================
extern void softirq_init();
extern void raise_softirq(uint64_t sirq_num);
extern int register_softirq(uint32_t irq_num, void (*action)(void *data), void *data);
extern int unregister_softirq(uint32_t irq_num);
extern void set_softirq_pending(uint64_t status);
extern void clear_softirq_pending(uint32_t irq_num);
extern void do_softirq();
// for temporary
#define MAX_SOFTIRQ_NUM 64
#define TIMER_SIRQ 0 // 时钟软中断号
#define VIDEO_REFRESH_SIRQ 1 // 帧缓冲区刷新软中断
/**
* @brief 发起软中断
*
*/
#define raise_softirq(sirq_num) \
do \
{ \
set_softirq_pending(1 << sirq_num); \
} while (0);
struct softirq_t
{
void (*action)(void *data); // 软中断处理函数
void *data;
};
/**
* @brief 软中断注册函数
*
* @param irq_num 软中断号
* @param action 响应函数
* @param data 响应数据结构体
*/
void register_softirq(uint32_t irq_num, void (*action)(void *data), void *data);
/**
* @brief 卸载软中断
*
* @param irq_num 软中断号
*/
void unregister_softirq(uint32_t irq_num);
void set_softirq_pending(uint64_t status);
uint64_t get_softirq_pending();
int clear_softirq_pending(uint32_t irq_num);
/**
* @brief 软中断处理程序
*
*/
void do_softirq();
void softirq_init();

View File

@ -0,0 +1,266 @@
use core::{ffi::c_void, ptr::null_mut};
use alloc::boxed::Box;
use crate::{
arch::interrupt::{cli, sti},
include::bindings::bindings::{verify_area, EBUSY, EEXIST, EPERM},
kBUG,
libs::spinlock::RawSpinlock,
};
const MAX_SOFTIRQ_NUM: u64 = 64;
const MAX_LOCK_TRIAL_TIME: u64 = 50;
pub static mut SOFTIRQ_HANDLER_PTR: *mut Softirq = null_mut();
/// 软中断向量号码
#[allow(dead_code)]
#[repr(u8)]
pub enum SoftirqNumber {
TIMER = 0, //时钟软中断信号
VideoRefresh = 1, //帧缓冲区刷新软中断
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct SoftirqVector {
pub action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>, //软中断处理函数
pub data: *mut c_void,
}
impl Default for SoftirqVector {
fn default() -> Self {
Self {
action: None,
data: null_mut(),
}
}
}
pub struct Softirq {
modify_lock: RawSpinlock,
pending: u64,
running: u64,
table: [SoftirqVector; MAX_SOFTIRQ_NUM as usize],
}
#[no_mangle]
#[allow(dead_code)]
/// @brief 提供给c的接口函数,用于初始化静态指针
pub extern "C" fn softirq_init() {
if unsafe { SOFTIRQ_HANDLER_PTR.is_null() } {
unsafe {
SOFTIRQ_HANDLER_PTR = Box::leak(Box::new(Softirq::default()));
}
} else {
kBUG!("Try to init SOFTIRQ_HANDLER_PTR twice.");
panic!("Try to init SOFTIRQ_HANDLER_PTR twice.");
}
}
/// @brief 将raw pointer转换为指针,减少unsafe块
#[inline]
pub fn __get_softirq_handler_mut() -> &'static mut Softirq {
return unsafe { SOFTIRQ_HANDLER_PTR.as_mut().unwrap() };
}
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn raise_softirq(sirq_num: u64) {
let softirq_handler = __get_softirq_handler_mut();
softirq_handler.set_softirq_pending(1 << sirq_num);
}
/// @brief 软中断注册函数
///
/// @param irq_num 软中断号
/// @param action 响应函数
/// @param data 响应数据结构体
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn register_softirq(
irq_num: u32,
action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>,
data: *mut c_void,
) {
let softirq_handler = __get_softirq_handler_mut();
softirq_handler.register_softirq(irq_num, action, data);
}
/// @brief 卸载软中断
/// @param irq_num 软中断号
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn unregister_softirq(irq_num: u32) {
let softirq_handler = __get_softirq_handler_mut();
softirq_handler.unregister_softirq(irq_num);
}
/// 设置软中断的运行状态只应在do_softirq中调用此宏
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn set_softirq_pending(irq_num: u32) {
let softirq_handler = __get_softirq_handler_mut();
softirq_handler.set_softirq_pending(irq_num);
}
/// @brief 设置软中断运行结束
///
/// @param softirq_num
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn clear_softirq_pending(irq_num: u32) {
let softirq_handler = __get_softirq_handler_mut();
softirq_handler.clear_softirq_pending(irq_num);
}
/// @brief 软中断处理程序
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn do_softirq() {
let softirq_handler = __get_softirq_handler_mut();
softirq_handler.do_softirq();
}
impl Default for Softirq {
fn default() -> Self {
Self {
modify_lock: RawSpinlock::INIT,
pending: (0),
running: (0),
table: [Default::default(); MAX_SOFTIRQ_NUM as usize],
}
}
}
impl Softirq {
#[inline]
#[allow(dead_code)]
pub fn get_softirq_pending(&self) -> u64 {
return self.pending;
}
#[inline]
#[allow(dead_code)]
pub fn get_softirq_running(&self) -> u64 {
return self.running;
}
#[inline]
pub fn set_softirq_pending(&mut self, softirq_num: u32) {
self.pending |= 1 << softirq_num;
}
#[inline]
pub fn set_softirq_running(&mut self, softirq_num: u32) {
self.running |= 1 << softirq_num;
}
#[inline]
pub fn clear_softirq_running(&mut self, softirq_num: u32) {
self.running &= !(1 << softirq_num);
}
/// @brief 清除软中断pending标志位
#[inline]
pub fn clear_softirq_pending(&mut self, softirq_num: u32) {
self.pending &= !(1 << softirq_num);
}
/// @brief 判断对应running标志位是否为0
/// @return true: 标志位为1; false: 标志位为0
#[inline]
pub fn is_running(&mut self, softirq_num: u32) -> bool {
return (self.running & (1 << softirq_num)).ne(&0);
}
/// @brief 判断对应pending标志位是否为0
/// @return true: 标志位为1; false: 标志位为0
#[inline]
pub fn is_pending(&mut self, softirq_num: u32) -> bool {
return (self.pending & (1 << softirq_num)).ne(&0);
}
/// @brief 注册软中断向量
/// @param irq_num 中断向量号码
/// @param action 中断函数的入口地址
/// @param data 中断函数的操作数据
pub fn register_softirq(
&mut self,
irq_num: u32,
action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>,
data: *mut c_void,
) -> i32 {
if self.table[irq_num as usize].action.is_some() {
return -(EEXIST as i32);
}
if unsafe { verify_area(action.unwrap() as u64, 1) } {
return -(EPERM as i32);
}
self.modify_lock.lock();
self.table[irq_num as usize].action = action;
self.table[irq_num as usize].data = data;
self.modify_lock.unlock();
return 0;
}
/// @brief 解注册软中断向量
/// @param irq_num 中断向量号码
pub fn unregister_softirq(&mut self, irq_num: u32) -> i32 {
for _trial_time in 0..MAX_LOCK_TRIAL_TIME {
if self.is_running(irq_num) {
continue; //running标志位为1
}
if self.modify_lock.try_lock() {
if self.is_running(irq_num) {
self.modify_lock.unlock();
continue;
}
break;
}
}
// 存在尝试加锁规定次数后仍加锁失败的情况,报告错误并退出
if !self.modify_lock.is_locked() {
return -(EBUSY as i32);
}
self.clear_softirq_running(irq_num);
self.clear_softirq_pending(irq_num);
self.table[irq_num as usize].action = None;
self.table[irq_num as usize].data = null_mut();
self.modify_lock.unlock();
return 0;
}
/// @brief 遍历执行软中断
pub fn do_softirq(&mut self) {
sti();
let mut softirq_index: u32 = 0; //软中断向量号码
while (softirq_index as u64) < MAX_SOFTIRQ_NUM && self.pending != 0 {
if self.is_pending(softirq_index)
&& self.table[softirq_index as usize].action.is_some()
&& !self.is_running(softirq_index)
{
if self.modify_lock.try_lock() {
if self.is_running(softirq_index)
|| self.table[softirq_index as usize].action.is_none()
{
self.modify_lock.unlock();
continue;
}
self.clear_softirq_pending(softirq_index);
self.set_softirq_running(softirq_index);
self.modify_lock.unlock();
unsafe {
(self.table[softirq_index as usize].action.unwrap())(
self.table[softirq_index as usize].data,
);
}
self.clear_softirq_running(softirq_index);
}
}
softirq_index += 1;
}
cli();
}
}

View File

@ -4,7 +4,7 @@
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]
#![feature(drain_filter)] // 允许Vec的drain_filter特性
#![feature(c_void_variant)] //not stable, used in /home/su/Documents/VSCode/DragonOS/kernel/src/exception/softirq.rs
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
@ -28,6 +28,7 @@ mod process;
mod sched;
mod smp;
mod time;
mod exception;
extern crate alloc;

View File

@ -52,7 +52,8 @@ void reload_gdt()
gdtp.size = bsp_gdt_size - 1;
gdtp.gdt_vaddr = (ul)phys_2_virt((ul)&GDT_Table);
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp) : "memory");
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp)
: "memory");
}
void reload_idt()
@ -63,7 +64,8 @@ void reload_idt()
// kdebug("gdtvaddr=%#018lx", p.gdt_vaddr);
// kdebug("gdt size=%d", p.size);
asm volatile("lidt (%0) \n\t" ::"r"(&idtp) : "memory");
asm volatile("lidt (%0) \n\t" ::"r"(&idtp)
: "memory");
}
// 初始化系统各模块
@ -124,17 +126,18 @@ void system_initialize()
irq_init();
softirq_init();
current_pcb->cpu_id = 0;
current_pcb->preempt_count = 0;
// 先初始化系统调用模块
syscall_init();
io_mfence();
// 再初始化进程模块。顺序不能调转
// sched_init();
io_mfence();
timer_init();
// 这里必须加内存屏障,否则会出错
io_mfence();
smp_init();
@ -143,7 +146,7 @@ void system_initialize()
vfs_init();
devfs_init();
procfs_init();
cpu_init();
ps2_keyboard_init();
tty_init();
@ -167,11 +170,12 @@ void system_initialize()
// 启用double buffer
// scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread
io_mfence();
// fat32_init();
HPET_enable();
io_mfence();
// 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行
apic_timer_init();
io_mfence();
@ -180,7 +184,7 @@ void system_initialize()
// pause();
}
//操作系统内核从这里开始执行
// 操作系统内核从这里开始执行
void Start_Kernel(void)
{

View File

@ -1,6 +1,6 @@
#![allow(dead_code)]
use crate::driver::timers::rtc::rtc::{rtc_get_cmos_time, rtc_time_t};
use crate::driver::timers::rtc::rtc::RtcTime;
#[allow(non_camel_case_types)]
pub type ktime_t = i64;
@ -15,17 +15,15 @@ fn ktime_to_ns(kt: ktime_t) -> i64 {
/// 时间戳为从UTC+0 1970-01-01 00:00到当前UTC+0时间所经过的纳秒数。
/// 注意由于当前未引入时区因此本函数默认时区为UTC+8来计算
fn ktime_get_real() -> ktime_t {
let mut rtc_time: rtc_time_t = rtc_time_t {
second: (0),
minute: (0),
hour: (0),
day: (0),
month: (0),
year: (0),
};
let mut rtc_time: RtcTime = RtcTime::default();
//调用rtc.h里面的函数
rtc_get_cmos_time(&mut rtc_time);
{
let r = rtc_time.get();
// 返回错误码
if r.is_err() {
return r.unwrap_err() as ktime_t;
}
}
let mut day_count: i32 = 0;
for year in 1970..rtc_time.year {