mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 12:16:31 +00:00
实现gettimeofday()系统调用和clocksource+timekeeping子模块 (#278)
- 实现gettimeofday()系统调用 - 实现clocksource+timekeeping子模块部分功能 - 实现了timespec转换成日期时间
This commit is contained in:
@ -17,7 +17,7 @@ export ASFLAGS := --64
|
||||
LD_LIST := head.o
|
||||
|
||||
|
||||
kernel_subdirs := common driver process debug arch exception mm smp sched syscall ktest libs ipc io
|
||||
kernel_subdirs := common driver process debug arch exception mm smp sched syscall ktest libs ipc io time
|
||||
|
||||
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
use core::{arch::asm, ptr::read_volatile};
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub fn local_irq_save(flags: &mut u64) {
|
||||
pub fn local_irq_save() -> usize {
|
||||
let x: usize;
|
||||
unsafe {
|
||||
asm!("pushfq", "pop rax", "mov rax, {0}", "cli", out(reg)(*flags),);
|
||||
asm!("pushfq ; pop {} ; cli", out(reg) x, options(nostack));
|
||||
}
|
||||
x
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn local_irq_restore(flags: &u64) {
|
||||
let x = unsafe { read_volatile(flags) };
|
||||
|
||||
// 恢复先前保存的rflags的值x
|
||||
pub fn local_irq_restore(x: usize) {
|
||||
unsafe {
|
||||
asm!("push r15",
|
||||
"popfq", in("r15")(x));
|
||||
asm!("push {} ; popfq", in(reg) x, options(nostack));
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +79,7 @@ impl FpState {
|
||||
/// @brief 从用户态进入内核时,保存浮点寄存器,并关闭浮点功能
|
||||
pub fn fp_state_save(pcb: &mut process_control_block) {
|
||||
// 该过程中不允许中断
|
||||
let mut rflags: u64 = 0;
|
||||
local_irq_save(&mut rflags);
|
||||
let rflags = local_irq_save();
|
||||
|
||||
let fp: &mut FpState = if pcb.fp_state == null_mut() {
|
||||
let f = Box::leak(Box::new(FpState::default()));
|
||||
@ -112,14 +111,13 @@ pub fn fp_state_save(pcb: &mut process_control_block) {
|
||||
"mov cr4, rax" */
|
||||
)
|
||||
}
|
||||
local_irq_restore(&rflags);
|
||||
local_irq_restore(rflags);
|
||||
}
|
||||
|
||||
/// @brief 从内核态返回用户态时,恢复浮点寄存器,并开启浮点功能
|
||||
pub fn fp_state_restore(pcb: &mut process_control_block) {
|
||||
// 该过程中不允许中断
|
||||
let mut rflags: u64 = 0;
|
||||
local_irq_save(&mut rflags);
|
||||
let rflags = local_irq_save();
|
||||
|
||||
if pcb.fp_state == null_mut() {
|
||||
panic!("fp_state_restore: fp_state is null. pid={}", pcb.pid);
|
||||
@ -143,5 +141,5 @@ pub fn fp_state_restore(pcb: &mut process_control_block) {
|
||||
fp.restore();
|
||||
fp.clear();
|
||||
|
||||
local_irq_restore(&rflags);
|
||||
local_irq_restore(rflags);
|
||||
}
|
||||
|
@ -48,8 +48,7 @@ impl InterruptArch for X86_64InterruptArch {
|
||||
|
||||
unsafe fn save_and_disable_irq() -> IrqFlagsGuard {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let mut rflags: u64 = 0;
|
||||
local_irq_save(&mut rflags);
|
||||
let rflags = local_irq_save() as u64;
|
||||
let flags = IrqFlags::new(rflags);
|
||||
let guard = IrqFlagsGuard::new(flags);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
@ -58,7 +57,7 @@ impl InterruptArch for X86_64InterruptArch {
|
||||
|
||||
unsafe fn restore_irq(flags: IrqFlags) {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
local_irq_restore(&flags.flags());
|
||||
local_irq_restore(flags.flags() as usize);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
@ -67,3 +67,10 @@ extern struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM];
|
||||
* @return uint32_t 当前cpu核心晶振频率
|
||||
*/
|
||||
uint32_t cpu_get_core_crysral_freq();
|
||||
|
||||
/**
|
||||
* @brief 获取处理器的tsc频率(单位:hz)
|
||||
*
|
||||
* @return uint64_t
|
||||
*/
|
||||
uint64_t cpu_get_tsc_freq();
|
@ -207,12 +207,13 @@ void HPET_enable()
|
||||
// kdebug("[HPET0] conf register after modify=%#018lx", ((*(uint64_t *)(HPET_REG_BASE + TIM0_CONF))));
|
||||
// kdebug("[HPET1] conf register =%#018lx", ((*(uint64_t *)(HPET_REG_BASE + TIM1_CONF))));
|
||||
|
||||
kinfo("HPET0 enabled.");
|
||||
|
||||
__write8b(HPET_REG_BASE + GEN_CONF, 3); // 置位旧设备中断路由兼容标志位、定时器组使能标志位
|
||||
io_mfence();
|
||||
// 注册中断
|
||||
irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0");
|
||||
io_mfence();
|
||||
__write8b(HPET_REG_BASE + GEN_CONF, 3); // 置位旧设备中断路由兼容标志位、定时器组使能标志位
|
||||
kinfo("HPET0 enabled.");
|
||||
|
||||
io_mfence();
|
||||
}
|
||||
|
||||
int HPET_init()
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
arch::interrupt::{cli, sti},
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
include::bindings::bindings::{io_in8, io_out8},
|
||||
syscall::SystemError,
|
||||
};
|
||||
@ -33,7 +34,7 @@ impl RtcTime {
|
||||
///@return int 成功则为0
|
||||
pub fn get(&mut self) -> Result<i32, SystemError> {
|
||||
// 为防止中断请求打断该过程,需要先关中断
|
||||
cli();
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
//0x0B
|
||||
let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B
|
||||
let is_24h: bool = if (status_register_b & 0x02) != 0 {
|
||||
@ -81,7 +82,7 @@ impl RtcTime {
|
||||
self.hour = ((self.hour & 0x7f) + 12) % 24;
|
||||
} // 将十二小时制转为24小时
|
||||
|
||||
sti();
|
||||
drop(irq_guard);
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
@ -225,15 +225,14 @@ impl Softirq {
|
||||
}
|
||||
|
||||
pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
|
||||
let mut flags = 0;
|
||||
local_irq_save(&mut flags);
|
||||
let flags = local_irq_save();
|
||||
let processor_id = smp_get_processor_id() as usize;
|
||||
|
||||
cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
local_irq_restore(&flags);
|
||||
local_irq_restore(flags);
|
||||
// kdebug!("raise_softirq exited");
|
||||
}
|
||||
pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
|
||||
|
@ -46,4 +46,5 @@
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
#include <smp/smp.h>
|
||||
#include <time/clocksource.h>
|
||||
#include <time/sleep.h>
|
||||
|
@ -120,3 +120,12 @@ uint32_t cpu_get_core_crysral_freq()
|
||||
|
||||
return c;
|
||||
}
|
||||
/**
|
||||
* @brief 获取处理器的tsc频率(单位:hz)
|
||||
*
|
||||
* @return uint64_t
|
||||
*/
|
||||
uint64_t cpu_get_tsc_freq()
|
||||
{
|
||||
return Cpu_tsc_freq;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use crate::syscall::SystemError;
|
||||
/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||
#[inline]
|
||||
pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) {
|
||||
local_irq_save(flags);
|
||||
*flags = local_irq_save() as u64;
|
||||
unsafe {
|
||||
spin_lock(lock);
|
||||
}
|
||||
@ -27,7 +27,7 @@ pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) {
|
||||
spin_unlock(lock);
|
||||
}
|
||||
// kdebug!("123");
|
||||
local_irq_restore(flags);
|
||||
local_irq_restore(*flags as usize);
|
||||
}
|
||||
|
||||
/// 判断一个自旋锁是否已经被加锁
|
||||
@ -130,14 +130,14 @@ impl RawSpinlock {
|
||||
|
||||
/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||
pub fn lock_irqsave(&self, flags: &mut u64) {
|
||||
local_irq_save(flags);
|
||||
*flags = local_irq_save() as u64;
|
||||
self.lock();
|
||||
}
|
||||
|
||||
/// @brief 恢复rflags以及中断状态并解锁自旋锁
|
||||
pub fn unlock_irqrestore(&self, flags: &u64) {
|
||||
self.unlock();
|
||||
local_irq_restore(flags);
|
||||
local_irq_restore(*flags as usize);
|
||||
}
|
||||
|
||||
/// @brief 尝试保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||
@ -145,11 +145,11 @@ impl RawSpinlock {
|
||||
/// 加锁失败->false
|
||||
#[inline(always)]
|
||||
pub fn try_lock_irqsave(&self, flags: &mut u64) -> bool {
|
||||
local_irq_save(flags);
|
||||
*flags = local_irq_save() as u64;
|
||||
if self.try_lock() {
|
||||
return true;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
local_irq_restore(*flags as usize);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,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()
|
||||
@ -62,7 +63,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,15 +126,21 @@ void system_initialize()
|
||||
|
||||
current_pcb->cpu_id = 0;
|
||||
current_pcb->preempt_count = 0;
|
||||
// 先初始化系统调用模块
|
||||
|
||||
syscall_init();
|
||||
|
||||
io_mfence();
|
||||
// 再初始化进程模块。顺序不能调转
|
||||
// sched_init();
|
||||
|
||||
rs_timekeeping_init();
|
||||
io_mfence();
|
||||
|
||||
rs_timer_init();
|
||||
io_mfence();
|
||||
|
||||
rs_jiffies_init();
|
||||
io_mfence();
|
||||
|
||||
rs_clocksource_boot_finish();
|
||||
// 这里必须加内存屏障,否则会出错
|
||||
io_mfence();
|
||||
smp_init();
|
||||
|
@ -15,13 +15,16 @@ use super::socket::{SOCKET_SET, SOCKET_WAITQUEUE};
|
||||
/// The network poll function, which will be called by timer.
|
||||
///
|
||||
/// The main purpose of this function is to poll all network interfaces.
|
||||
struct NetWorkPollFunc();
|
||||
#[derive(Debug)]
|
||||
struct NetWorkPollFunc;
|
||||
|
||||
impl TimerFunction for NetWorkPollFunc {
|
||||
fn run(&mut self) {
|
||||
fn run(&mut self) -> Result<(), SystemError> {
|
||||
poll_ifaces_try_lock(10).ok();
|
||||
let next_time = next_n_ms_timer_jiffies(10);
|
||||
let timer = Timer::new(Box::new(NetWorkPollFunc()), next_time);
|
||||
let timer = Timer::new(Box::new(NetWorkPollFunc), next_time);
|
||||
timer.activate();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +32,7 @@ pub fn net_init() -> Result<(), SystemError> {
|
||||
dhcp_query()?;
|
||||
// Init poll timer function
|
||||
let next_time = next_n_ms_timer_jiffies(5);
|
||||
let timer = Timer::new(Box::new(NetWorkPollFunc()), next_time);
|
||||
let timer = Timer::new(Box::new(NetWorkPollFunc), next_time);
|
||||
timer.activate();
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -859,7 +859,8 @@ void process_exit_thread(struct process_control_block *pcb)
|
||||
int process_release_pcb(struct process_control_block *pcb)
|
||||
{
|
||||
// 释放子进程的页表
|
||||
process_exit_mm(pcb);
|
||||
// BUG 暂时注释process_exit_mm
|
||||
// process_exit_mm(pcb);
|
||||
if ((pcb->flags & PF_KTHREAD)) // 释放内核线程的worker private结构体
|
||||
free_kthread_struct(pcb);
|
||||
|
||||
|
@ -16,7 +16,10 @@ use crate::{
|
||||
io::SeekFrom,
|
||||
kinfo,
|
||||
net::syscall::SockAddr,
|
||||
time::TimeSpec,
|
||||
time::{
|
||||
syscall::{PosixTimeZone, PosixTimeval, SYS_TIMEZONE},
|
||||
TimeSpec,
|
||||
},
|
||||
};
|
||||
|
||||
#[repr(i32)]
|
||||
@ -354,6 +357,7 @@ pub const SYS_ACCEPT: usize = 40;
|
||||
|
||||
pub const SYS_GETSOCKNAME: usize = 41;
|
||||
pub const SYS_GETPEERNAME: usize = 42;
|
||||
pub const SYS_GETTIMEOFDAY: usize = 43;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Syscall;
|
||||
@ -867,6 +871,43 @@ impl Syscall {
|
||||
SYS_GETPEERNAME => {
|
||||
Self::getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32)
|
||||
}
|
||||
SYS_GETTIMEOFDAY => {
|
||||
let timeval = args[0] as *mut PosixTimeval;
|
||||
let timezone_ptr = args[1] as *const PosixTimeZone;
|
||||
let security_check = || {
|
||||
if unsafe {
|
||||
verify_area(timeval as u64, core::mem::size_of::<PosixTimeval>() as u64)
|
||||
} == false
|
||||
{
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
if unsafe {
|
||||
verify_area(
|
||||
timezone_ptr as u64,
|
||||
core::mem::size_of::<PosixTimeZone>() as u64,
|
||||
)
|
||||
} == false
|
||||
{
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
return Ok(());
|
||||
};
|
||||
let r = security_check();
|
||||
if r.is_err() {
|
||||
Err(r.unwrap_err())
|
||||
} else {
|
||||
let timezone = if !timezone_ptr.is_null() {
|
||||
&SYS_TIMEZONE
|
||||
} else {
|
||||
unsafe { timezone_ptr.as_ref().unwrap() }
|
||||
};
|
||||
if !timeval.is_null() {
|
||||
Self::gettimeofday(timeval, timezone)
|
||||
} else {
|
||||
Err(SystemError::EFAULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||
};
|
||||
|
||||
|
@ -53,3 +53,6 @@
|
||||
#define SYS_ACCEPT 40 // 接受一个socket连接
|
||||
#define SYS_GETSOCKNAME 41 // 获取socket的名字
|
||||
#define SYS_GETPEERNAME 42 // 获取socket的对端名字
|
||||
#define SYS_GETTIMEOFDAY 43 // 获取当前时间
|
||||
|
||||
#define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用
|
8
kernel/src/time/Makefile
Normal file
8
kernel/src/time/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
|
||||
all: clocksource.o
|
||||
|
||||
clocksource.o: clocksource.c
|
||||
$(CC) $(CFLAGS) -c clocksource.c -o clocksource.o
|
8
kernel/src/time/clocksource.c
Normal file
8
kernel/src/time/clocksource.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include "clocksource.h"
|
||||
#include <common/kthread.h>
|
||||
|
||||
void run_watchdog_kthread()
|
||||
{
|
||||
kdebug("run_watchdog_kthread");
|
||||
kthread_run(rs_clocksource_watchdog_kthread, NULL, "clocksource_watchdog");
|
||||
}
|
8
kernel/src/time/clocksource.h
Normal file
8
kernel/src/time/clocksource.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/kthread.h>
|
||||
|
||||
extern int rs_clocksource_watchdog_kthread(void *_data);
|
||||
extern void rs_clocksource_boot_finish();
|
||||
|
||||
void run_watchdog_kthread();
|
850
kernel/src/time/clocksource.rs
Normal file
850
kernel/src/time/clocksource.rs
Normal file
@ -0,0 +1,850 @@
|
||||
use core::{
|
||||
ffi::c_void,
|
||||
fmt::Debug,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc, vec::Vec};
|
||||
use lazy_static::__Deref;
|
||||
|
||||
use crate::{
|
||||
include::bindings::bindings::run_watchdog_kthread, kdebug, kinfo, libs::spinlock::SpinLock,
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use super::{
|
||||
jiffies::clocksource_default_clock,
|
||||
timer::{clock, Timer, TimerFunction},
|
||||
NSEC_PER_SEC,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
/// linked list with the registered clocksources
|
||||
pub static ref CLOCKSOURCE_LIST: SpinLock<LinkedList<Arc<dyn Clocksource>>> =
|
||||
SpinLock::new(LinkedList::new());
|
||||
/// 被监视中的时钟源
|
||||
pub static ref WATCHDOG_LIST: SpinLock<LinkedList<Arc<dyn Clocksource>>> =
|
||||
SpinLock::new(LinkedList::new());
|
||||
|
||||
pub static ref CLOCKSOUCE_WATCHDOG:SpinLock<ClocksouceWatchdog> = SpinLock::new(ClocksouceWatchdog::new());
|
||||
|
||||
pub static ref OVERRIDE_NAME: SpinLock<String> = SpinLock::new(String::from(""));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// 正在被使用时钟源
|
||||
pub static CUR_CLOCKSOURCE: SpinLock<Option<Arc<dyn Clocksource>>> = SpinLock::new(None);
|
||||
/// 是否完成加载
|
||||
pub static mut FINISHED_BOOTING: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Interval: 0.5sec Threshold: 0.0625s
|
||||
/// 系统节拍率
|
||||
pub const HZ: u64 = 1000;
|
||||
/// watchdog检查间隔
|
||||
pub const WATCHDOG_INTERVAL: u64 = HZ >> 1;
|
||||
/// 最大能接受的误差大小
|
||||
pub const WATCHDOG_THRESHOLD: u32 = NSEC_PER_SEC >> 4;
|
||||
|
||||
// 时钟周期数
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct CycleNum(pub u64);
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl CycleNum {
|
||||
#[inline(always)]
|
||||
pub fn new(cycle: u64) -> Self {
|
||||
Self(cycle)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn data(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn add(&self, other: CycleNum) -> CycleNum {
|
||||
CycleNum(self.data() + other.data())
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn div(&self, other: CycleNum) -> CycleNum {
|
||||
CycleNum(self.data() - other.data())
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ClocksourceMask: u64 {
|
||||
}
|
||||
/// 时钟状态标记
|
||||
#[derive(Default)]
|
||||
pub struct ClocksourceFlags: u64 {
|
||||
/// 表示时钟设备是连续的
|
||||
const CLOCK_SOURCE_IS_CONTINUOUS = 0x01;
|
||||
/// 表示该时钟源需要经过watchdog检查
|
||||
const CLOCK_SOURCE_MUST_VERIFY = 0x02;
|
||||
/// 表示该时钟源是watchdog
|
||||
const CLOCK_SOURCE_WATCHDOG = 0x10;
|
||||
/// 表示该时钟源是高分辨率的
|
||||
const CLOCK_SOURCE_VALID_FOR_HRES = 0x20;
|
||||
/// 表示该时钟源误差过大
|
||||
const CLOCK_SOURCE_UNSTABLE = 0x40;
|
||||
}
|
||||
}
|
||||
impl From<u64> for ClocksourceMask {
|
||||
fn from(value: u64) -> Self {
|
||||
if value < 64 {
|
||||
return Self::from_bits_truncate((1 << value) - 1);
|
||||
}
|
||||
return Self::from_bits_truncate(u64::MAX);
|
||||
}
|
||||
}
|
||||
impl ClocksourceMask {
|
||||
pub fn new(b: u64) -> Self {
|
||||
Self { bits: b }
|
||||
}
|
||||
}
|
||||
impl ClocksourceFlags {
|
||||
pub fn new(b: u64) -> Self {
|
||||
Self { bits: b }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClocksouceWatchdog {
|
||||
/// 监视器
|
||||
watchdog: Option<Arc<dyn Clocksource>>,
|
||||
/// 检查器是否在工作的标志
|
||||
is_running: bool,
|
||||
/// 上一次检查的时刻
|
||||
last_check: CycleNum,
|
||||
/// 定时监视器的过期时间
|
||||
timer_expires: u64,
|
||||
}
|
||||
impl ClocksouceWatchdog {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
watchdog: None,
|
||||
is_running: false,
|
||||
last_check: CycleNum(0),
|
||||
timer_expires: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取watchdog
|
||||
fn get_watchdog(&mut self) -> &mut Option<Arc<dyn Clocksource>> {
|
||||
&mut self.watchdog
|
||||
}
|
||||
|
||||
/// 启用检查器
|
||||
pub fn clocksource_start_watchdog(&mut self) {
|
||||
// 如果watchdog未被设置或者已经启用了就退出
|
||||
let watchdog_list = &WATCHDOG_LIST.lock();
|
||||
if self.is_running || self.watchdog.is_none() || watchdog_list.is_empty() {
|
||||
return;
|
||||
}
|
||||
// 生成一个定时器
|
||||
let wd_timer_func: Box<WatchdogTimerFunc> = Box::new(WatchdogTimerFunc {});
|
||||
self.timer_expires += clock() + WATCHDOG_INTERVAL;
|
||||
self.last_check = self.watchdog.as_ref().unwrap().clone().read();
|
||||
let wd_timer = Timer::new(wd_timer_func, self.timer_expires);
|
||||
wd_timer.activate();
|
||||
self.is_running = true;
|
||||
}
|
||||
|
||||
/// 停止检查器
|
||||
/// list_len WATCHDOG_LIST长度
|
||||
pub fn clocksource_stop_watchdog(&mut self, list_len: usize) {
|
||||
if !self.is_running || (self.watchdog.is_some() && list_len != 0) {
|
||||
return;
|
||||
}
|
||||
// TODO 当实现了周期性的定时器后 需要将监视用的定时器删除
|
||||
self.is_running = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 定时检查器
|
||||
#[derive(Debug)]
|
||||
pub struct WatchdogTimerFunc;
|
||||
impl TimerFunction for WatchdogTimerFunc {
|
||||
fn run(&mut self) -> Result<(), SystemError> {
|
||||
return clocksource_watchdog();
|
||||
}
|
||||
}
|
||||
|
||||
/// 时钟源的特性
|
||||
pub trait Clocksource: Send + Sync + Debug {
|
||||
// TODO 返回值类型可能需要改变
|
||||
/// returns a cycle value, passes clocksource as argument
|
||||
fn read(&self) -> CycleNum;
|
||||
/// optional function to enable the clocksource
|
||||
fn enable(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
/// optional function to disable the clocksource
|
||||
fn disable(&self) -> Result<(), SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
/// vsyscall based read
|
||||
fn vread(&self) -> Result<CycleNum, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
/// suspend function for the clocksource, if necessary
|
||||
fn suspend(&self) -> Result<(), SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
/// resume function for the clocksource, if necessary
|
||||
fn resume(&self) -> Result<(), SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 获取时钟源数据
|
||||
fn clocksource_data(&self) -> ClocksourceData;
|
||||
|
||||
fn update_clocksource_data(&self, _data: ClocksourceData) -> Result<(), SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 获取时钟源
|
||||
fn clocksource(&self) -> Arc<dyn Clocksource>;
|
||||
}
|
||||
|
||||
/// # 实现整数log2的运算
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * `x` - 要计算的数字
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// * `u32` - 返回\log_2(x)的值
|
||||
fn log2(x: u32) -> u32 {
|
||||
let mut result = 0;
|
||||
let mut x = x;
|
||||
|
||||
if x >= 1 << 16 {
|
||||
x >>= 16;
|
||||
result |= 16;
|
||||
}
|
||||
if x >= 1 << 8 {
|
||||
x >>= 8;
|
||||
result |= 8;
|
||||
}
|
||||
if x >= 1 << 4 {
|
||||
x >>= 4;
|
||||
result |= 4;
|
||||
}
|
||||
if x >= 1 << 2 {
|
||||
x >>= 2;
|
||||
result |= 2;
|
||||
}
|
||||
if x >= 1 << 1 {
|
||||
result |= 1;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
impl dyn Clocksource {
|
||||
/// # 计算时钟源能记录的最大时间跨度
|
||||
pub fn clocksource_max_deferment(&self) -> u64 {
|
||||
let cs_data_guard = self.clocksource_data();
|
||||
let max_nsecs: u64;
|
||||
let mut max_cycles: u64;
|
||||
max_cycles = (1 << (63 - (log2(cs_data_guard.mult) + 1))) as u64;
|
||||
max_cycles = max_cycles.min(cs_data_guard.mask.bits);
|
||||
max_nsecs = clocksource_cyc2ns(
|
||||
CycleNum(max_cycles),
|
||||
cs_data_guard.mult,
|
||||
cs_data_guard.shift,
|
||||
);
|
||||
return max_nsecs - (max_nsecs >> 5);
|
||||
}
|
||||
|
||||
/// # 注册时钟源
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// * `Ok(0)` - 时钟源注册成功。
|
||||
/// * `Err(SystemError)` - 时钟源注册失败。
|
||||
pub fn register(&self) -> Result<i32, SystemError> {
|
||||
let ns = self.clocksource_max_deferment();
|
||||
let mut cs_data = self.clocksource_data();
|
||||
cs_data.max_idle_ns = ns as u32;
|
||||
self.update_clocksource_data(cs_data)?;
|
||||
// 将时钟源加入到时钟源队列中
|
||||
self.clocksource_enqueue();
|
||||
// 将时钟源加入到监视队列中
|
||||
self.clocksource_enqueue_watchdog()
|
||||
.expect("register: failed to enqueue watchdog list");
|
||||
// 选择一个最好的时钟源
|
||||
clocksource_select();
|
||||
kdebug!("clocksource_register successfully");
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// # 将时钟源插入时钟源队列
|
||||
pub fn clocksource_enqueue(&self) {
|
||||
// 根据rating由大到小排序
|
||||
let cs_data = self.clocksource_data();
|
||||
let list_guard = &mut CLOCKSOURCE_LIST.lock();
|
||||
let mut spilt_pos: usize = 0;
|
||||
for (pos, ele) in list_guard.iter().enumerate() {
|
||||
if ele.clocksource_data().rating < cs_data.rating {
|
||||
spilt_pos = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut temp_list = list_guard.split_off(spilt_pos);
|
||||
let cs = self.clocksource();
|
||||
list_guard.push_back(cs);
|
||||
list_guard.append(&mut temp_list);
|
||||
// kdebug!(
|
||||
// "CLOCKSOURCE_LIST len = {:?},clocksource_enqueue sccessfully",
|
||||
// list_guard.len()
|
||||
// );
|
||||
}
|
||||
|
||||
/// # 将时间源插入监控队列
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// * `Ok(0)` - 时间源插入监控队列成功
|
||||
/// * `Err(SystemError)` - 时间源插入监控队列失败
|
||||
pub fn clocksource_enqueue_watchdog(&self) -> Result<i32, SystemError> {
|
||||
// BUG 可能需要lock irq
|
||||
let mut cs_data = self.clocksource_data();
|
||||
|
||||
let cs = self.clocksource();
|
||||
if cs_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY)
|
||||
{
|
||||
let mut list_guard = WATCHDOG_LIST.lock_irqsave();
|
||||
// cs是被监视的
|
||||
cs_data
|
||||
.flags
|
||||
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
|
||||
cs.update_clocksource_data(cs_data)?;
|
||||
list_guard.push_back(cs);
|
||||
} else {
|
||||
// cs是监视器
|
||||
if cs_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS)
|
||||
{
|
||||
// 如果时钟设备是连续的
|
||||
cs_data
|
||||
.flags
|
||||
.insert(ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES);
|
||||
cs.update_clocksource_data(cs_data.clone())?;
|
||||
}
|
||||
|
||||
// 将时钟源加入到监控队列中
|
||||
let mut list_guard = WATCHDOG_LIST.lock();
|
||||
list_guard.push_back(cs.clone());
|
||||
drop(list_guard);
|
||||
|
||||
// 对比当前注册的时间源的精度和监视器的精度
|
||||
let cs_watchdog = &mut CLOCKSOUCE_WATCHDOG.lock();
|
||||
if cs_watchdog.watchdog.is_none()
|
||||
|| cs_data.rating
|
||||
> cs_watchdog
|
||||
.watchdog
|
||||
.clone()
|
||||
.unwrap()
|
||||
.clocksource_data()
|
||||
.rating
|
||||
{
|
||||
// 当前注册的时间源的精度更高或者没有监视器,替换监视器
|
||||
cs_watchdog.watchdog.replace(cs);
|
||||
clocksource_reset_watchdog();
|
||||
}
|
||||
|
||||
// 启动监视器
|
||||
cs_watchdog.clocksource_start_watchdog();
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// # 将时钟源标记为unstable
|
||||
///
|
||||
/// ## 参数
|
||||
/// * `delta` - 时钟源误差
|
||||
pub fn set_unstable(&self, delta: i64) -> Result<i32, SystemError> {
|
||||
let mut cs_data = self.clocksource_data();
|
||||
// 打印出unstable的时钟源信息
|
||||
kdebug!(
|
||||
"clocksource :{:?} is unstable, its delta is {:?}",
|
||||
cs_data.name,
|
||||
delta
|
||||
);
|
||||
cs_data.flags.remove(
|
||||
ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES | ClocksourceFlags::CLOCK_SOURCE_WATCHDOG,
|
||||
);
|
||||
cs_data
|
||||
.flags
|
||||
.insert(ClocksourceFlags::CLOCK_SOURCE_UNSTABLE);
|
||||
self.update_clocksource_data(cs_data)?;
|
||||
|
||||
// 启动watchdog线程 进行后续处理
|
||||
if unsafe { FINISHED_BOOTING.load(Ordering::Relaxed) } {
|
||||
// TODO 在实现了工作队列后,将启动线程换成schedule work
|
||||
unsafe { run_watchdog_kthread() }
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// # 将时间源从监视链表中弹出
|
||||
fn clocksource_dequeue_watchdog(&self) {
|
||||
let data = self.clocksource_data();
|
||||
let mut locked_watchdog = CLOCKSOUCE_WATCHDOG.lock();
|
||||
let watchdog = locked_watchdog
|
||||
.get_watchdog()
|
||||
.clone()
|
||||
.unwrap()
|
||||
.clocksource_data();
|
||||
|
||||
let mut list = WATCHDOG_LIST.lock();
|
||||
let mut size = list.len();
|
||||
|
||||
let mut del_pos: usize = size;
|
||||
for (pos, ele) in list.iter().enumerate() {
|
||||
let ele_data = ele.clocksource_data();
|
||||
if ele_data.name.eq(&data.name) && ele_data.rating.eq(&data.rating) {
|
||||
// 记录要删除的时钟源在监视链表中的下标
|
||||
del_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
if data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY)
|
||||
{
|
||||
// 如果时钟源是需要被检查的,直接删除时钟源
|
||||
if del_pos != size {
|
||||
let mut temp_list = list.split_off(del_pos);
|
||||
temp_list.pop_front();
|
||||
list.append(&mut temp_list);
|
||||
}
|
||||
} else if watchdog.name.eq(&data.name) && watchdog.rating.eq(&data.rating) {
|
||||
// 如果要删除的时钟源是监视器,则需要找到一个新的监视器
|
||||
// TODO 重新设置时钟源
|
||||
// 将链表解锁防止reset中双重加锁 并释放保存的旧的watchdog的数据
|
||||
|
||||
// 代替了clocksource_reset_watchdog()的功能,将所有时钟源的watchdog标记清除
|
||||
for ele in list.iter() {
|
||||
ele.clocksource_data()
|
||||
.flags
|
||||
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
|
||||
}
|
||||
|
||||
// 遍历所有时间源,寻找新的监视器
|
||||
let mut clocksource_list = CLOCKSOURCE_LIST.lock();
|
||||
let mut replace_pos: usize = clocksource_list.len();
|
||||
for (pos, ele) in clocksource_list.iter().enumerate() {
|
||||
let ele_data = ele.clocksource_data();
|
||||
|
||||
if ele_data.name.eq(&data.name) && ele_data.rating.eq(&data.rating)
|
||||
|| ele_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY)
|
||||
{
|
||||
// 当前时钟源是要被删除的时钟源或没被检查过的时钟源
|
||||
// 不适合成为监视器
|
||||
continue;
|
||||
}
|
||||
let watchdog = locked_watchdog.get_watchdog().clone();
|
||||
if watchdog.is_none()
|
||||
|| ele_data.rating > watchdog.unwrap().clocksource_data().rating
|
||||
{
|
||||
// 如果watchdog不存在或者当前时钟源的精度高于watchdog的精度,则记录当前时钟源的下标
|
||||
replace_pos = pos;
|
||||
}
|
||||
}
|
||||
// 使用刚刚找到的更好的时钟源替换旧的watchdog
|
||||
if replace_pos < clocksource_list.len() {
|
||||
let mut temp_list = clocksource_list.split_off(replace_pos);
|
||||
let new_wd = temp_list.front().unwrap().clone();
|
||||
clocksource_list.append(&mut temp_list);
|
||||
// 替换watchdog
|
||||
locked_watchdog.watchdog.replace(new_wd);
|
||||
// drop(locked_watchdog);
|
||||
}
|
||||
// 删除时钟源
|
||||
if del_pos != size {
|
||||
let mut temp_list = list.split_off(del_pos);
|
||||
temp_list.pop_front();
|
||||
list.append(&mut temp_list);
|
||||
}
|
||||
}
|
||||
|
||||
// 清除watchdog标记
|
||||
let mut cs_data = self.clocksource_data();
|
||||
cs_data
|
||||
.flags
|
||||
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
|
||||
self.update_clocksource_data(cs_data)
|
||||
.expect("clocksource_dequeue_watchdog: failed to update clocksource data");
|
||||
size = list.len();
|
||||
// 停止当前的watchdog
|
||||
locked_watchdog.clocksource_stop_watchdog(size - 1);
|
||||
}
|
||||
|
||||
/// # 将时钟源从时钟源链表中弹出
|
||||
fn clocksource_dequeue(&self) {
|
||||
let mut list = CLOCKSOURCE_LIST.lock();
|
||||
let data = self.clocksource_data();
|
||||
let mut del_pos: usize = list.len();
|
||||
for (pos, ele) in list.iter().enumerate() {
|
||||
let ele_data = ele.clocksource_data();
|
||||
if ele_data.name.eq(&data.name) && ele_data.rating.eq(&data.rating) {
|
||||
// 记录时钟源在链表中的下标
|
||||
del_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
// 删除时钟源
|
||||
if del_pos != list.len() {
|
||||
let mut temp_list = list.split_off(del_pos);
|
||||
temp_list.pop_front();
|
||||
list.append(&mut temp_list);
|
||||
}
|
||||
}
|
||||
|
||||
/// # 注销时钟源
|
||||
#[allow(dead_code)]
|
||||
pub fn unregister(&self) {
|
||||
// 将时钟源从监视链表中弹出
|
||||
self.clocksource_dequeue_watchdog();
|
||||
// 将时钟源从时钟源链表中弹出
|
||||
self.clocksource_dequeue();
|
||||
// 检查是否有更好的时钟源
|
||||
clocksource_select();
|
||||
}
|
||||
/// # 修改时钟源的精度
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * `rating` - 指定的时钟精度
|
||||
fn clocksource_change_rating(&self, rating: i32) {
|
||||
// 将时钟源从链表中弹出
|
||||
self.clocksource_dequeue();
|
||||
let mut data = self.clocksource_data();
|
||||
// 修改时钟源的精度
|
||||
data.set_rating(rating);
|
||||
self.update_clocksource_data(data)
|
||||
.expect("clocksource_change_rating:updata clocksource failed");
|
||||
// 插入时钟源到时钟源链表中
|
||||
self.clocksource_enqueue();
|
||||
// 检查是否有更好的时钟源
|
||||
clocksource_select();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClocksourceData {
|
||||
/// 时钟源名字
|
||||
pub name: String,
|
||||
/// 时钟精度
|
||||
pub rating: i32,
|
||||
pub mask: ClocksourceMask,
|
||||
pub mult: u32,
|
||||
pub shift: u32,
|
||||
pub max_idle_ns: u32,
|
||||
pub flags: ClocksourceFlags,
|
||||
pub watchdog_last: CycleNum,
|
||||
}
|
||||
|
||||
impl ClocksourceData {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(
|
||||
name: String,
|
||||
rating: i32,
|
||||
mask: ClocksourceMask,
|
||||
mult: u32,
|
||||
shift: u32,
|
||||
max_idle_ns: u32,
|
||||
flags: ClocksourceFlags,
|
||||
) -> Self {
|
||||
let csd = ClocksourceData {
|
||||
name,
|
||||
rating,
|
||||
mask,
|
||||
mult,
|
||||
shift,
|
||||
max_idle_ns,
|
||||
flags,
|
||||
watchdog_last: CycleNum(0),
|
||||
};
|
||||
return csd;
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
self.name = name;
|
||||
}
|
||||
pub fn set_rating(&mut self, rating: i32) {
|
||||
self.rating = rating;
|
||||
}
|
||||
pub fn set_mask(&mut self, mask: ClocksourceMask) {
|
||||
self.mask = mask;
|
||||
}
|
||||
pub fn set_mult(&mut self, mult: u32) {
|
||||
self.mult = mult;
|
||||
}
|
||||
pub fn set_shift(&mut self, shift: u32) {
|
||||
self.shift = shift;
|
||||
}
|
||||
pub fn set_max_idle_ns(&mut self, max_idle_ns: u32) {
|
||||
self.max_idle_ns = max_idle_ns;
|
||||
}
|
||||
pub fn set_flags(&mut self, flags: ClocksourceFlags) {
|
||||
self.flags = flags;
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_flags(&mut self, flags: ClocksourceFlags) {
|
||||
self.flags.remove(flags)
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub fn insert_flags(&mut self, flags: ClocksourceFlags) {
|
||||
self.flags.insert(flags)
|
||||
}
|
||||
}
|
||||
|
||||
/// converts clocksource cycles to nanoseconds
|
||||
///
|
||||
pub fn clocksource_cyc2ns(cycles: CycleNum, mult: u32, shift: u32) -> u64 {
|
||||
return (cycles.data() * mult as u64) >> shift;
|
||||
}
|
||||
|
||||
/// # 重启所有的时间源
|
||||
#[allow(dead_code)]
|
||||
pub fn clocksource_resume() {
|
||||
let list = CLOCKSOURCE_LIST.lock();
|
||||
for ele in list.iter() {
|
||||
let data = ele.clocksource_data();
|
||||
match ele.resume() {
|
||||
Ok(_) => continue,
|
||||
Err(_) => {
|
||||
kdebug!("clocksource {:?} resume failed", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
clocksource_resume_watchdog();
|
||||
}
|
||||
|
||||
/// # 暂停所有的时间源
|
||||
#[allow(dead_code)]
|
||||
pub fn clocksource_suspend() {
|
||||
let list = CLOCKSOURCE_LIST.lock();
|
||||
for ele in list.iter() {
|
||||
let data = ele.clocksource_data();
|
||||
match ele.suspend() {
|
||||
Ok(_) => continue,
|
||||
Err(_) => {
|
||||
kdebug!("clocksource {:?} suspend failed", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # 根据watchdog的精度,来检查被监视的时钟源的误差
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// * `Ok()` - 检查完成
|
||||
/// * `Err(SystemError)` - 错误码
|
||||
pub fn clocksource_watchdog() -> Result<(), SystemError> {
|
||||
let mut cs_watchdog = CLOCKSOUCE_WATCHDOG.lock();
|
||||
|
||||
// watchdog没有在运行的话直接退出
|
||||
if !cs_watchdog.is_running || cs_watchdog.watchdog.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
let cur_watchdog = cs_watchdog.watchdog.as_ref().unwrap().clone();
|
||||
let cur_wd_data = cur_watchdog.as_ref().clocksource_data();
|
||||
let cur_wd_nowclock = cur_watchdog.as_ref().read().data();
|
||||
|
||||
let wd_last = cs_watchdog.last_check.data();
|
||||
let wd_dev_nsec = clocksource_cyc2ns(
|
||||
CycleNum((cur_wd_nowclock - wd_last) & cur_wd_data.mask.bits),
|
||||
cur_wd_data.mult,
|
||||
cur_wd_data.shift,
|
||||
);
|
||||
cs_watchdog.last_check = CycleNum(cur_wd_nowclock);
|
||||
drop(cs_watchdog);
|
||||
let watchdog_list = &mut WATCHDOG_LIST.lock();
|
||||
for cs in watchdog_list.iter() {
|
||||
let mut cs_data = cs.clocksource_data();
|
||||
// 判断时钟源是否已经被标记为不稳定
|
||||
if cs_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_UNSTABLE)
|
||||
{
|
||||
// 启动watchdog_kthread
|
||||
unsafe { run_watchdog_kthread() };
|
||||
continue;
|
||||
}
|
||||
// 读取时钟源现在的时间
|
||||
let cs_now_clock = cs.read();
|
||||
|
||||
// 如果时钟源没有被监视,则开始监视他
|
||||
if !cs_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG)
|
||||
{
|
||||
cs_data
|
||||
.flags
|
||||
.insert(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
|
||||
// 记录此次检查的时刻
|
||||
cs_data.watchdog_last = cs_now_clock;
|
||||
cs.update_clocksource_data(cs_data.clone())?;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算时钟源的误差
|
||||
let cs_dev_nsec = clocksource_cyc2ns(
|
||||
CycleNum(cs_now_clock.div(cs_data.watchdog_last).data() & cs_data.mask.bits),
|
||||
cs_data.mult,
|
||||
cs_data.shift,
|
||||
);
|
||||
// 记录此次检查的时刻
|
||||
cs_data.watchdog_last = cs_now_clock;
|
||||
cs.update_clocksource_data(cs_data.clone())?;
|
||||
if cs_dev_nsec.abs_diff(wd_dev_nsec) > WATCHDOG_THRESHOLD.into() {
|
||||
// 误差过大,标记为unstable
|
||||
cs.set_unstable((cs_dev_nsec - wd_dev_nsec).try_into().unwrap())?;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断是否要切换为高精度模式
|
||||
if !cs_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES)
|
||||
&& cs_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS)
|
||||
&& cur_wd_data
|
||||
.flags
|
||||
.contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS)
|
||||
{
|
||||
cs_data
|
||||
.flags
|
||||
.insert(ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES);
|
||||
cs.update_clocksource_data(cs_data)?;
|
||||
// TODO 通知tick机制 切换为高精度模式
|
||||
}
|
||||
let mut cs_watchdog = CLOCKSOUCE_WATCHDOG.lock();
|
||||
// FIXME 需要保证所有cpu时间统一
|
||||
cs_watchdog.timer_expires += WATCHDOG_INTERVAL;
|
||||
//创建定时器执行watchdog
|
||||
let watchdog_func = Box::new(WatchdogTimerFunc {});
|
||||
let watchdog_timer = Timer::new(watchdog_func, cs_watchdog.timer_expires);
|
||||
watchdog_timer.activate();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// # watchdog线程的逻辑,执行unstable的后续操作
|
||||
pub fn clocksource_watchdog_kthread() {
|
||||
let mut del_vec: Vec<usize> = Vec::new();
|
||||
let mut del_clocks: Vec<Arc<dyn Clocksource>> = Vec::new();
|
||||
let wd_list = &mut WATCHDOG_LIST.lock();
|
||||
|
||||
// 将不稳定的时钟源弹出监视链表
|
||||
for (pos, ele) in wd_list.iter().enumerate() {
|
||||
let data = ele.clocksource_data();
|
||||
if data.flags.contains(ClocksourceFlags::CLOCK_SOURCE_UNSTABLE) {
|
||||
del_vec.push(pos);
|
||||
del_clocks.push(ele.clone());
|
||||
}
|
||||
}
|
||||
for pos in del_vec {
|
||||
let mut temp_list = wd_list.split_off(pos);
|
||||
temp_list.pop_front();
|
||||
wd_list.append(&mut temp_list);
|
||||
}
|
||||
|
||||
// 检查是否需要停止watchdog
|
||||
CLOCKSOUCE_WATCHDOG
|
||||
.lock()
|
||||
.clocksource_stop_watchdog(wd_list.len());
|
||||
// 将不稳定的时钟源精度都设置为最低
|
||||
for clock in del_clocks.iter() {
|
||||
clock.clocksource_change_rating(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// # 清空所有时钟源的watchdog标志位
|
||||
pub fn clocksource_reset_watchdog() {
|
||||
let list_guard = WATCHDOG_LIST.lock();
|
||||
for ele in list_guard.iter() {
|
||||
ele.clocksource_data()
|
||||
.flags
|
||||
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
|
||||
}
|
||||
}
|
||||
|
||||
/// # 重启检查器
|
||||
pub fn clocksource_resume_watchdog() {
|
||||
clocksource_reset_watchdog();
|
||||
}
|
||||
|
||||
/// # 根据精度选择最优的时钟源,或者接受用户指定的时间源
|
||||
pub fn clocksource_select() {
|
||||
let list_guard = CLOCKSOURCE_LIST.lock();
|
||||
if unsafe { FINISHED_BOOTING.load(Ordering::Relaxed) } || list_guard.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut best = list_guard.front().unwrap().clone();
|
||||
let override_name = OVERRIDE_NAME.lock();
|
||||
// 判断是否有用户空间指定的时间源
|
||||
for ele in list_guard.iter() {
|
||||
if ele.clocksource_data().name.eq(override_name.deref()) {
|
||||
// TODO 判断是否是高精度模式
|
||||
// 暂时不支持高精度模式
|
||||
// 如果是高精度模式,但是时钟源不支持高精度模式的话,就要退出循环
|
||||
best = ele.clone();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 对比当前的时钟源和记录到最好的时钟源的精度
|
||||
if CUR_CLOCKSOURCE.lock().as_ref().is_some() {
|
||||
// 当前时钟源不为空
|
||||
let cur_clocksource = CUR_CLOCKSOURCE.lock().as_ref().unwrap().clone();
|
||||
let best_name = &best.clocksource_data().name;
|
||||
if cur_clocksource.clocksource_data().name.ne(best_name) {
|
||||
kinfo!("Switching to the clocksource {:?}\n", best_name);
|
||||
drop(cur_clocksource);
|
||||
CUR_CLOCKSOURCE.lock().replace(best);
|
||||
// TODO 通知timerkeeping 切换了时间源
|
||||
}
|
||||
} else {
|
||||
// 当前时钟源为空
|
||||
CUR_CLOCKSOURCE.lock().replace(best);
|
||||
}
|
||||
kdebug!(" clocksource_select finish");
|
||||
}
|
||||
|
||||
/// # clocksource模块加载完成
|
||||
pub fn clocksource_boot_finish() {
|
||||
let mut cur_clocksource = CUR_CLOCKSOURCE.lock();
|
||||
cur_clocksource.replace(clocksource_default_clock());
|
||||
unsafe { FINISHED_BOOTING.store(true, Ordering::Relaxed) };
|
||||
// 清除不稳定的时钟源
|
||||
clocksource_watchdog_kthread();
|
||||
kdebug!("clocksource_boot_finish");
|
||||
}
|
||||
|
||||
// ======== 以下为对C的接口 ========
|
||||
/// # 完成对clocksource模块的加载
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_clocksource_boot_finish() {
|
||||
clocksource_boot_finish();
|
||||
}
|
||||
|
||||
/// # 启动watchdog线程的辅助函数
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_clocksource_watchdog_kthread(_data: c_void) -> i32 {
|
||||
clocksource_watchdog_kthread();
|
||||
return 0;
|
||||
}
|
3
kernel/src/time/jiffies.h
Normal file
3
kernel/src/time/jiffies.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
extern void rs_jiffies_init();
|
100
kernel/src/time/jiffies.rs
Normal file
100
kernel/src/time/jiffies.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use crate::{kdebug, libs::spinlock::SpinLock, syscall::SystemError};
|
||||
|
||||
use super::{
|
||||
clocksource::{Clocksource, ClocksourceData, ClocksourceFlags, ClocksourceMask, CycleNum, HZ},
|
||||
timer::clock,
|
||||
NSEC_PER_SEC,
|
||||
};
|
||||
lazy_static! {
|
||||
pub static ref DEFAULT_CLOCK: Arc<ClocksourceJiffies> = ClocksourceJiffies::new();
|
||||
}
|
||||
pub const CLOCK_TICK_RATE: u32 = HZ as u32 * 100000;
|
||||
pub const JIFFIES_SHIFT: u32 = 8;
|
||||
pub const LATCH: u32 = ((CLOCK_TICK_RATE + (HZ as u32) / 2) / HZ as u32) as u32;
|
||||
pub const ACTHZ: u32 = sh_div(CLOCK_TICK_RATE, LATCH, 8);
|
||||
pub const NSEC_PER_JIFFY: u32 = ((NSEC_PER_SEC << 8) / ACTHZ) as u32;
|
||||
pub const fn sh_div(nom: u32, den: u32, lsh: u32) -> u32 {
|
||||
(((nom) / (den)) << (lsh)) + ((((nom) % (den)) << (lsh)) + (den) / 2) / (den)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClocksourceJiffies(SpinLock<InnerJiffies>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InnerJiffies {
|
||||
data: ClocksourceData,
|
||||
self_ref: Weak<ClocksourceJiffies>,
|
||||
}
|
||||
|
||||
impl Clocksource for ClocksourceJiffies {
|
||||
fn read(&self) -> CycleNum {
|
||||
CycleNum(clock())
|
||||
}
|
||||
|
||||
fn clocksource_data(&self) -> ClocksourceData {
|
||||
let inner = self.0.lock();
|
||||
return inner.data.clone();
|
||||
}
|
||||
|
||||
fn clocksource(&self) -> Arc<dyn Clocksource> {
|
||||
self.0.lock().self_ref.upgrade().unwrap()
|
||||
}
|
||||
fn update_clocksource_data(&self, _data: ClocksourceData) -> Result<(), SystemError> {
|
||||
let d = &mut self.0.lock().data;
|
||||
d.set_flags(_data.flags);
|
||||
d.set_mask(_data.mask);
|
||||
d.set_max_idle_ns(_data.max_idle_ns);
|
||||
d.set_mult(_data.mult);
|
||||
d.set_name(_data.name);
|
||||
d.set_rating(_data.rating);
|
||||
d.set_shift(_data.shift);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn enable(&self) -> Result<i32, SystemError> {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
impl ClocksourceJiffies {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let data = ClocksourceData {
|
||||
name: "jiffies".to_string(),
|
||||
rating: 1,
|
||||
mask: ClocksourceMask::new(0xffffffff),
|
||||
mult: NSEC_PER_JIFFY << JIFFIES_SHIFT,
|
||||
shift: JIFFIES_SHIFT,
|
||||
max_idle_ns: Default::default(),
|
||||
flags: ClocksourceFlags::new(0),
|
||||
watchdog_last: CycleNum(0),
|
||||
};
|
||||
let jieffies = Arc::new(ClocksourceJiffies(SpinLock::new(InnerJiffies {
|
||||
data,
|
||||
self_ref: Default::default(),
|
||||
})));
|
||||
jieffies.0.lock().self_ref = Arc::downgrade(&jieffies);
|
||||
|
||||
return jieffies;
|
||||
}
|
||||
}
|
||||
pub fn clocksource_default_clock() -> Arc<ClocksourceJiffies> {
|
||||
DEFAULT_CLOCK.clone()
|
||||
}
|
||||
|
||||
pub fn jiffies_init() {
|
||||
//注册jiffies
|
||||
let jiffies = clocksource_default_clock() as Arc<dyn Clocksource>;
|
||||
match jiffies.register() {
|
||||
Ok(_) => kdebug!("jiffies_init sccessfully"),
|
||||
Err(_) => kdebug!("jiffies_init failed, no default clock running"),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_jiffies_init() {
|
||||
jiffies_init();
|
||||
}
|
@ -2,11 +2,14 @@ use core::{fmt, ops};
|
||||
|
||||
use self::timekeep::ktime_get_real_ns;
|
||||
|
||||
pub mod clocksource;
|
||||
pub mod jiffies;
|
||||
pub mod sleep;
|
||||
pub mod syscall;
|
||||
pub mod timeconv;
|
||||
pub mod timekeep;
|
||||
pub mod timekeeping;
|
||||
pub mod timer;
|
||||
|
||||
/* Time structures. (Partitially taken from smoltcp)
|
||||
|
||||
The `time` module contains structures used to represent both
|
||||
@ -18,6 +21,20 @@ absolute and relative time.
|
||||
[Instant]: struct.Instant.html
|
||||
[Duration]: struct.Duration.html
|
||||
*/
|
||||
#[allow(dead_code)]
|
||||
pub const MSEC_PER_SEC: u32 = 1000;
|
||||
#[allow(dead_code)]
|
||||
pub const USEC_PER_MSEC: u32 = 1000;
|
||||
#[allow(dead_code)]
|
||||
pub const NSEC_PER_USEC: u32 = 1000;
|
||||
#[allow(dead_code)]
|
||||
pub const NSEC_PER_MSEC: u32 = 1000000;
|
||||
#[allow(dead_code)]
|
||||
pub const USEC_PER_SEC: u32 = 1000000;
|
||||
#[allow(dead_code)]
|
||||
pub const NSEC_PER_SEC: u32 = 1000000000;
|
||||
#[allow(dead_code)]
|
||||
pub const FSEC_PER_SEC: u64 = 1000000000000000;
|
||||
|
||||
/// 表示时间的结构体,符合POSIX标准。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
|
@ -1,10 +1,42 @@
|
||||
use core::ptr::null_mut;
|
||||
use core::{
|
||||
ffi::{c_int, c_longlong},
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
kdebug,
|
||||
syscall::{Syscall, SystemError},
|
||||
time::{sleep::nanosleep, TimeSpec},
|
||||
};
|
||||
|
||||
use super::timekeeping::do_gettimeofday;
|
||||
|
||||
pub type PosixTimeT = c_longlong;
|
||||
pub type PosixSusecondsT = c_int;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct PosixTimeval {
|
||||
pub tv_sec: PosixTimeT,
|
||||
pub tv_usec: PosixSusecondsT,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug)]
|
||||
/// 当前时区信息
|
||||
pub struct PosixTimeZone {
|
||||
/// 格林尼治相对于当前时区相差的分钟数
|
||||
pub tz_minuteswest: c_int,
|
||||
/// DST矫正时差
|
||||
pub tz_dsttime: c_int,
|
||||
}
|
||||
|
||||
/// 系统时区 暂时写定为东八区
|
||||
pub const SYS_TIMEZONE: PosixTimeZone = PosixTimeZone {
|
||||
tz_minuteswest: -480,
|
||||
tz_dsttime: 0,
|
||||
};
|
||||
|
||||
impl Syscall {
|
||||
/// @brief 休眠指定时间(单位:纳秒)(提供给C的接口)
|
||||
///
|
||||
@ -44,4 +76,22 @@ impl Syscall {
|
||||
pub fn clock() -> Result<usize, SystemError> {
|
||||
return Ok(super::timer::clock() as usize);
|
||||
}
|
||||
|
||||
pub fn gettimeofday(
|
||||
tv: *mut PosixTimeval,
|
||||
_timezone: &PosixTimeZone,
|
||||
) -> Result<usize, SystemError> {
|
||||
// TODO; 处理时区信息
|
||||
kdebug!("enter sys_do_gettimeofday");
|
||||
if tv == null_mut() {
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
let posix_time = do_gettimeofday();
|
||||
unsafe {
|
||||
(*tv).tv_sec = posix_time.tv_sec;
|
||||
(*tv).tv_usec = posix_time.tv_usec;
|
||||
}
|
||||
kdebug!("exit sys_do_gettimeofday");
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
143
kernel/src/time/timeconv.rs
Normal file
143
kernel/src/time/timeconv.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use super::syscall::PosixTimeT;
|
||||
/// 一小时所包含的秒数
|
||||
const SECS_PER_HOUR: i64 = 60 * 60;
|
||||
/// 一天所包含的秒数
|
||||
const SECS_PER_DAY: i64 = SECS_PER_HOUR * 24;
|
||||
/// 每年中每个月最后一天所对应天数
|
||||
const MON_OF_YDAY: [[i64; 13]; 2] = [
|
||||
// 普通年
|
||||
[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365],
|
||||
// 闰年
|
||||
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366],
|
||||
];
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct CalendarTime {
|
||||
tm_sec: i32,
|
||||
tm_min: i32,
|
||||
tm_hour: i32,
|
||||
tm_mday: i32,
|
||||
tm_mon: i32,
|
||||
tm_wday: i32,
|
||||
tm_yday: i32,
|
||||
tm_year: i32,
|
||||
}
|
||||
impl CalendarTime {
|
||||
pub fn new() -> Self {
|
||||
CalendarTime {
|
||||
tm_year: Default::default(),
|
||||
tm_sec: Default::default(),
|
||||
tm_min: Default::default(),
|
||||
tm_hour: Default::default(),
|
||||
tm_mday: Default::default(),
|
||||
tm_mon: Default::default(),
|
||||
tm_wday: Default::default(),
|
||||
tm_yday: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # 判断是否是闰年
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * 'year' - 年份
|
||||
fn is_leap(year: u32) -> bool {
|
||||
let mut flag = false;
|
||||
if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 {
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// # 计算除法
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// * 'left' - 被除数
|
||||
/// * 'right' - 除数
|
||||
fn math_div(left: u32, right: u32) -> u32 {
|
||||
return left / right;
|
||||
}
|
||||
|
||||
/// # 计算两年之间的闰年数目
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * 'y1' - 起始年份
|
||||
/// * 'y2' - 结束年份
|
||||
fn leaps_between(y1: u32, y2: u32) -> u32 {
|
||||
// 算出y1之前的闰年数量
|
||||
let y1_leaps = math_div(y1 - 1, 4) - math_div(y1 - 1, 100) + math_div(y1 - 1, 400);
|
||||
// 算出y2之前的闰年数量
|
||||
let y2_leaps = math_div(y2 - 1, 4) - math_div(y2 - 1, 100) + math_div(y2 - 1, 400);
|
||||
|
||||
y2_leaps - y1_leaps
|
||||
}
|
||||
|
||||
/// # 将秒数转换成日期
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * 'totalsecs' - 1970年1月1日 00:00:00 UTC到现在的秒数
|
||||
/// * 'offset' - 指定的秒数对应的时间段(含)的偏移量(以秒为单位)
|
||||
#[allow(dead_code)]
|
||||
pub fn time_to_calendar(totalsecs: PosixTimeT, offset: i32) -> CalendarTime {
|
||||
let mut result = CalendarTime::new();
|
||||
// 计算对应的天数
|
||||
let mut days = totalsecs / SECS_PER_DAY;
|
||||
// 一天中剩余的秒数
|
||||
let mut rem = totalsecs % SECS_PER_DAY;
|
||||
|
||||
// 加入偏移量
|
||||
rem += offset as i64;
|
||||
while rem < 0 {
|
||||
rem += SECS_PER_DAY;
|
||||
days -= 1;
|
||||
}
|
||||
while rem >= SECS_PER_DAY {
|
||||
rem -= SECS_PER_DAY;
|
||||
days += 1;
|
||||
}
|
||||
// 计算对应的小时数
|
||||
result.tm_hour = (rem / SECS_PER_HOUR) as i32;
|
||||
rem = rem % SECS_PER_HOUR;
|
||||
|
||||
// 计算对应的分钟数
|
||||
result.tm_min = (rem / 60) as i32;
|
||||
rem = rem % 60;
|
||||
|
||||
// 秒数
|
||||
result.tm_sec = rem as i32;
|
||||
|
||||
// totalsec是从1970年1月1日 00:00:00 UTC到现在的秒数
|
||||
// 当时是星期四
|
||||
result.tm_wday = ((4 + days) % 7) as i32;
|
||||
|
||||
let mut year = 1970;
|
||||
while days < 0 || (is_leap(year) && days >= 366) || (!is_leap(year) && days >= 365) {
|
||||
// 假设每一年都是365天,计算出大概的年份
|
||||
let guess_year = year + math_div(days.try_into().unwrap(), 365);
|
||||
// 将已经计算过的天数去掉
|
||||
days -= ((guess_year - year) * 365 + leaps_between(year, guess_year)) as i64;
|
||||
year = guess_year;
|
||||
}
|
||||
result.tm_year = (year - 1900) as i32;
|
||||
result.tm_yday = days as i32;
|
||||
let mut il = 0;
|
||||
if is_leap(year) {
|
||||
il = 1
|
||||
};
|
||||
let mut mon = 0;
|
||||
for i in MON_OF_YDAY[il] {
|
||||
if days < i {
|
||||
break;
|
||||
}
|
||||
mon += 1;
|
||||
}
|
||||
days -= MON_OF_YDAY[il][mon - 1];
|
||||
result.tm_mon = (mon - 1) as i32;
|
||||
result.tm_mday = (days + 1) as i32;
|
||||
|
||||
result
|
||||
}
|
3
kernel/src/time/timekeeping.h
Normal file
3
kernel/src/time/timekeeping.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
extern void rs_timekeeping_init();
|
312
kernel/src/time/timekeeping.rs
Normal file
312
kernel/src/time/timekeeping.rs
Normal file
@ -0,0 +1,312 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, Ordering};
|
||||
use x86_64::align_up;
|
||||
|
||||
use crate::{
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
kdebug,
|
||||
libs::rwlock::RwLock,
|
||||
time::{jiffies::clocksource_default_clock, timekeep::ktime_get_real_ns, TimeSpec},
|
||||
};
|
||||
|
||||
use super::{
|
||||
clocksource::{clocksource_cyc2ns, Clocksource, CycleNum, HZ},
|
||||
syscall::PosixTimeval,
|
||||
NSEC_PER_SEC, USEC_PER_SEC,
|
||||
};
|
||||
/// NTP周期频率
|
||||
pub const NTP_INTERVAL_FREQ: u64 = HZ;
|
||||
/// NTP周期长度
|
||||
pub const NTP_INTERVAL_LENGTH: u64 = NSEC_PER_SEC as u64 / NTP_INTERVAL_FREQ;
|
||||
/// NTP转换比例
|
||||
pub const NTP_SCALE_SHIFT: u32 = 32;
|
||||
|
||||
/// timekeeping休眠标志,false为未休眠
|
||||
pub static TIMEKEEPING_SUSPENDED: AtomicBool = AtomicBool::new(false);
|
||||
/// 已经递增的微秒数
|
||||
static __ADDED_USEC: AtomicI64 = AtomicI64::new(0);
|
||||
/// 已经递增的秒数
|
||||
static __ADDED_SEC: AtomicI64 = AtomicI64::new(0);
|
||||
/// timekeeper全局变量,用于管理timekeeper模块
|
||||
static mut __TIMEKEEPER: Option<Timekeeper> = None;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Timekeeper(RwLock<TimekeeperData>);
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct TimekeeperData {
|
||||
/// 用于计时的当前时钟源。
|
||||
clock: Option<Arc<dyn Clocksource>>,
|
||||
/// 当前时钟源的移位值。
|
||||
shift: i32,
|
||||
/// 一个NTP间隔中的时钟周期数。
|
||||
cycle_interval: CycleNum,
|
||||
/// 一个NTP间隔中时钟移位的纳秒数。
|
||||
xtime_interval: u64,
|
||||
///
|
||||
xtime_remainder: i64,
|
||||
/// 每个NTP间隔累积的原始纳米秒
|
||||
raw_interval: i64,
|
||||
/// 时钟移位纳米秒余数
|
||||
xtime_nsec: u64,
|
||||
/// 积累时间和ntp时间在ntp位移纳秒量上的差距
|
||||
ntp_error: i64,
|
||||
/// 用于转换时钟偏移纳秒和ntp偏移纳秒的偏移量
|
||||
ntp_error_shift: i32,
|
||||
/// NTP调整时钟乘法器
|
||||
mult: u32,
|
||||
raw_time: TimeSpec,
|
||||
wall_to_monotonic: TimeSpec,
|
||||
total_sleep_time: TimeSpec,
|
||||
xtime: TimeSpec,
|
||||
}
|
||||
impl TimekeeperData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
clock: None,
|
||||
shift: Default::default(),
|
||||
cycle_interval: CycleNum(0),
|
||||
xtime_interval: Default::default(),
|
||||
xtime_remainder: Default::default(),
|
||||
raw_interval: Default::default(),
|
||||
xtime_nsec: Default::default(),
|
||||
ntp_error: Default::default(),
|
||||
ntp_error_shift: Default::default(),
|
||||
mult: Default::default(),
|
||||
xtime: TimeSpec {
|
||||
tv_nsec: 0,
|
||||
tv_sec: 0,
|
||||
},
|
||||
wall_to_monotonic: TimeSpec {
|
||||
tv_nsec: 0,
|
||||
tv_sec: 0,
|
||||
},
|
||||
total_sleep_time: TimeSpec {
|
||||
tv_nsec: 0,
|
||||
tv_sec: 0,
|
||||
},
|
||||
raw_time: TimeSpec {
|
||||
tv_nsec: 0,
|
||||
tv_sec: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Timekeeper {
|
||||
/// # 设置timekeeper的参数
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * 'clock' - 指定的时钟实际类型。初始为ClocksourceJiffies
|
||||
pub fn timekeeper_setup_internals(&self, clock: Arc<dyn Clocksource>) {
|
||||
let mut timekeeper = self.0.write();
|
||||
// 更新clock
|
||||
let mut clock_data = clock.clocksource_data();
|
||||
clock_data.watchdog_last = clock.read();
|
||||
if clock.update_clocksource_data(clock_data).is_err() {
|
||||
kdebug!("timekeeper_setup_internals:update_clocksource_data run failed");
|
||||
}
|
||||
timekeeper.clock.replace(clock.clone());
|
||||
|
||||
let clock_data = clock.clocksource_data();
|
||||
let mut temp = NTP_INTERVAL_LENGTH << clock_data.shift;
|
||||
let ntpinterval = temp;
|
||||
temp += (clock_data.mult / 2) as u64;
|
||||
// do div
|
||||
|
||||
timekeeper.cycle_interval = CycleNum(temp);
|
||||
timekeeper.xtime_interval = temp * clock_data.mult as u64;
|
||||
timekeeper.xtime_remainder = (ntpinterval - timekeeper.xtime_interval) as i64;
|
||||
timekeeper.raw_interval = (timekeeper.xtime_interval >> clock_data.shift) as i64;
|
||||
timekeeper.xtime_nsec = 0;
|
||||
timekeeper.shift = clock_data.shift as i32;
|
||||
|
||||
timekeeper.ntp_error = 0;
|
||||
timekeeper.ntp_error_shift = (NTP_SCALE_SHIFT - clock_data.shift) as i32;
|
||||
|
||||
timekeeper.mult = clock_data.mult;
|
||||
}
|
||||
|
||||
/// # 获取当前时钟源距离上次检测走过的纳秒数
|
||||
#[allow(dead_code)]
|
||||
pub fn tk_get_ns(&self) -> u64 {
|
||||
let timekeeper = self.0.read();
|
||||
let clock = timekeeper.clock.clone().unwrap();
|
||||
let clock_now = clock.read();
|
||||
let clcok_data = clock.clocksource_data();
|
||||
let clock_delta = clock_now.div(clcok_data.watchdog_last).data() & clcok_data.mask.bits();
|
||||
return clocksource_cyc2ns(CycleNum(clock_delta), clcok_data.mult, clcok_data.shift);
|
||||
}
|
||||
}
|
||||
pub fn timekeeper() -> &'static Timekeeper {
|
||||
return unsafe { __TIMEKEEPER.as_ref().unwrap() };
|
||||
}
|
||||
|
||||
pub fn timekeeper_init() {
|
||||
unsafe { __TIMEKEEPER = Some(Timekeeper(RwLock::new(TimekeeperData::new()))) };
|
||||
}
|
||||
|
||||
/// # 获取1970.1.1至今的UTC时间戳(最小单位:nsec)
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// * 'TimeSpec' - 时间戳
|
||||
pub fn getnstimeofday() -> TimeSpec {
|
||||
kdebug!("enter getnstimeofday");
|
||||
|
||||
// let mut nsecs: u64 = 0;0
|
||||
let mut _xtime = TimeSpec {
|
||||
tv_nsec: 0,
|
||||
tv_sec: 0,
|
||||
};
|
||||
loop {
|
||||
match timekeeper().0.try_read() {
|
||||
None => continue,
|
||||
Some(tk) => {
|
||||
_xtime = tk.xtime;
|
||||
drop(tk);
|
||||
// nsecs = timekeeper().tk_get_ns();
|
||||
// TODO 不同架构可能需要加上不同的偏移量
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// xtime.tv_nsec += nsecs as i64;
|
||||
let sec = __ADDED_SEC.load(Ordering::SeqCst);
|
||||
_xtime.tv_sec += sec;
|
||||
while _xtime.tv_nsec >= NSEC_PER_SEC.into() {
|
||||
_xtime.tv_nsec -= NSEC_PER_SEC as i64;
|
||||
_xtime.tv_sec += 1;
|
||||
}
|
||||
|
||||
// TODO 将xtime和当前时间源的时间相加
|
||||
|
||||
return _xtime;
|
||||
}
|
||||
|
||||
/// # 获取1970.1.1至今的UTC时间戳(最小单位:usec)
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// * 'PosixTimeval' - 时间戳
|
||||
pub fn do_gettimeofday() -> PosixTimeval {
|
||||
let tp = getnstimeofday();
|
||||
return PosixTimeval {
|
||||
tv_sec: tp.tv_sec,
|
||||
tv_usec: (tp.tv_nsec / 1000) as i32,
|
||||
};
|
||||
}
|
||||
|
||||
/// # 初始化timekeeping模块
|
||||
pub fn timekeeping_init() {
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
timekeeper_init();
|
||||
|
||||
// TODO 有ntp模块后 在此初始化ntp模块
|
||||
|
||||
let clock = clocksource_default_clock();
|
||||
clock
|
||||
.enable()
|
||||
.expect("clocksource_default_clock enable failed");
|
||||
timekeeper().timekeeper_setup_internals(clock);
|
||||
// 暂时不支持其他架构平台对时间的设置 所以使用x86平台对应值初始化
|
||||
let mut timekeeper = timekeeper().0.write();
|
||||
timekeeper.xtime.tv_nsec = ktime_get_real_ns();
|
||||
|
||||
// 初始化wall time到monotonic的时间
|
||||
let mut nsec = -timekeeper.xtime.tv_nsec;
|
||||
let mut sec = -timekeeper.xtime.tv_sec;
|
||||
// FIXME: 这里有个奇怪的奇怪的bug
|
||||
let num = nsec % NSEC_PER_SEC as i64;
|
||||
nsec += num * NSEC_PER_SEC as i64;
|
||||
sec -= num;
|
||||
timekeeper.wall_to_monotonic.tv_nsec = nsec;
|
||||
timekeeper.wall_to_monotonic.tv_sec = sec;
|
||||
|
||||
__ADDED_USEC.store(0, Ordering::SeqCst);
|
||||
__ADDED_SEC.store(0, Ordering::SeqCst);
|
||||
|
||||
drop(irq_guard);
|
||||
kdebug!("timekeeping_init successfully");
|
||||
}
|
||||
|
||||
/// # 使用当前时钟源增加wall time
|
||||
pub fn update_wall_time() {
|
||||
let rsp = unsafe { crate::include::bindings::bindings::get_rsp() } as usize;
|
||||
let _stack_use = align_up(rsp as u64, 32768) - rsp as u64;
|
||||
|
||||
// kdebug!("enter update_wall_time, stack_use = {:}",stack_use);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
// 如果在休眠那就不更新
|
||||
if TIMEKEEPING_SUSPENDED.load(Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== 请不要删除这些注释 =====
|
||||
// let clock = timekeeper.clock.clone().unwrap();
|
||||
// let clock_data = clock.clocksource_data();
|
||||
// let offset = (clock.read().div(clock_data.watchdog_last).data()) & clock_data.mask.bits();
|
||||
|
||||
// timekeeper.xtime_nsec = (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
|
||||
// // TODO 当有ntp模块之后 需要将timekeep与ntp进行同步并检查
|
||||
// timekeeper.xtime.tv_nsec = ((timekeeper.xtime_nsec as i64) >> timekeeper.shift) + 1;
|
||||
// timekeeper.xtime_nsec -= (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
|
||||
|
||||
// timekeeper.xtime.tv_nsec += offset as i64;
|
||||
// while unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC.into()) {
|
||||
// timekeeper.xtime.tv_nsec -= NSEC_PER_SEC as i64;
|
||||
// timekeeper.xtime.tv_sec += 1;
|
||||
// // TODO 需要处理闰秒
|
||||
// }
|
||||
// ================
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
// 一分钟同步一次
|
||||
__ADDED_USEC.fetch_add(500, Ordering::SeqCst);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let mut retry = 10;
|
||||
|
||||
let usec = __ADDED_USEC.load(Ordering::SeqCst);
|
||||
if usec % USEC_PER_SEC as i64 == 0 {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
__ADDED_SEC.fetch_add(1, Ordering::SeqCst);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
loop {
|
||||
if (usec & !((1 << 26) - 1)) != 0 {
|
||||
if __ADDED_USEC
|
||||
.compare_exchange(usec, 0, Ordering::SeqCst, Ordering::SeqCst)
|
||||
.is_ok()
|
||||
|| retry == 0
|
||||
{
|
||||
// 同步时间
|
||||
// 我感觉这里会出问题:多个读者不退出的话,写者就无法写入
|
||||
// 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。
|
||||
let mut timekeeper = timekeeper().0.write();
|
||||
timekeeper.xtime.tv_nsec = ktime_get_real_ns();
|
||||
timekeeper.xtime.tv_sec = 0;
|
||||
__ADDED_SEC.store(0, Ordering::SeqCst);
|
||||
drop(timekeeper);
|
||||
break;
|
||||
}
|
||||
retry -= 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO 需要检查是否更新时间源
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
drop(irq_guard);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
// TODO timekeeping_adjust
|
||||
// TODO wall_to_monotic
|
||||
|
||||
// ========= 以下为对C的接口 =========
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_timekeeping_init() {
|
||||
timekeeping_init();
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <common/glib.h>
|
||||
#include <driver/timers/HPET/HPET.h>
|
||||
#include <common/kthread.h>
|
||||
|
||||
// 定义LONG_MAX为最大超时时间 - 允许负数
|
||||
#define MAX_TIMEOUT (int64_t)((1ul << 63) - 1)
|
||||
|
@ -1,4 +1,8 @@
|
||||
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
|
||||
use core::{
|
||||
fmt::Debug,
|
||||
intrinsics::unlikely,
|
||||
sync::atomic::{compiler_fence, AtomicBool, AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
@ -7,31 +11,33 @@ use alloc::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
asm::current::current_pcb,
|
||||
interrupt::{cli, sti},
|
||||
sched::sched,
|
||||
arch::{asm::current::current_pcb, sched::sched, CurrentIrqArch},
|
||||
exception::{
|
||||
softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
|
||||
InterruptArch,
|
||||
},
|
||||
exception::softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
|
||||
include::bindings::bindings::{process_control_block, process_wakeup, pt_regs, PROC_RUNNING},
|
||||
include::bindings::bindings::{process_control_block, process_wakeup, PROC_RUNNING},
|
||||
kdebug, kerror,
|
||||
libs::spinlock::SpinLock,
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use super::timekeeping::update_wall_time;
|
||||
|
||||
const MAX_TIMEOUT: i64 = i64::MAX;
|
||||
const TIMER_RUN_CYCLE_THRESHOLD: usize = 20;
|
||||
static mut TIMER_JIFFIES: u64 = 0;
|
||||
static TIMER_JIFFIES: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
lazy_static! {
|
||||
pub static ref TIMER_LIST: SpinLock<LinkedList<Arc<Timer>>> = SpinLock::new(LinkedList::new());
|
||||
}
|
||||
|
||||
/// 定时器要执行的函数的特征
|
||||
pub trait TimerFunction: Send + Sync {
|
||||
fn run(&mut self);
|
||||
pub trait TimerFunction: Send + Sync + Debug {
|
||||
fn run(&mut self) -> Result<(), SystemError>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// WakeUpHelper函数对应的结构体
|
||||
pub struct WakeUpHelper {
|
||||
pcb: &'static mut process_control_block,
|
||||
@ -44,13 +50,15 @@ impl WakeUpHelper {
|
||||
}
|
||||
|
||||
impl TimerFunction for WakeUpHelper {
|
||||
fn run(&mut self) {
|
||||
fn run(&mut self) -> Result<(), SystemError> {
|
||||
unsafe {
|
||||
process_wakeup(self.pcb);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Timer(SpinLock<InnerTimer>);
|
||||
|
||||
impl Timer {
|
||||
@ -97,6 +105,7 @@ impl Timer {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut temp_list: LinkedList<Arc<Timer>> = timer_list.split_off(split_pos);
|
||||
timer_list.push_back(inner_guard.self_ref.upgrade().unwrap());
|
||||
timer_list.append(&mut temp_list);
|
||||
@ -106,11 +115,18 @@ impl Timer {
|
||||
|
||||
#[inline]
|
||||
fn run(&self) {
|
||||
self.0.lock().timer_func.run();
|
||||
let r = self.0.lock().timer_func.run();
|
||||
if unlikely(r.is_err()) {
|
||||
kerror!(
|
||||
"Failed to run timer function: {self:?} {:?}",
|
||||
r.err().unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 定时器类型
|
||||
#[derive(Debug)]
|
||||
pub struct InnerTimer {
|
||||
/// 定时器结束时刻
|
||||
pub expire_jiffies: u64,
|
||||
@ -179,7 +195,7 @@ impl SoftirqVec for DoTimerSoftirq {
|
||||
continue;
|
||||
}
|
||||
let timer_list_front_guard = timer_list_front_guard.unwrap();
|
||||
if timer_list_front_guard.expire_jiffies > unsafe { TIMER_JIFFIES as u64 } {
|
||||
if timer_list_front_guard.expire_jiffies > TIMER_JIFFIES.load(Ordering::SeqCst) {
|
||||
drop(timer_list_front_guard);
|
||||
timer_list.push_front(timer_list_front);
|
||||
break;
|
||||
@ -205,11 +221,11 @@ pub fn timer_init() {
|
||||
|
||||
/// 计算接下来n毫秒对应的定时器时间片
|
||||
pub fn next_n_ms_timer_jiffies(expire_ms: u64) -> u64 {
|
||||
return unsafe { TIMER_JIFFIES as u64 } + 1000 * (expire_ms);
|
||||
return TIMER_JIFFIES.load(Ordering::SeqCst) + 1000 * (expire_ms);
|
||||
}
|
||||
/// 计算接下来n微秒对应的定时器时间片
|
||||
pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64 {
|
||||
return unsafe { TIMER_JIFFIES as u64 } + (expire_us);
|
||||
return TIMER_JIFFIES.load(Ordering::SeqCst) + (expire_us);
|
||||
}
|
||||
|
||||
/// @brief 让pcb休眠timeout个jiffies
|
||||
@ -229,15 +245,17 @@ pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
|
||||
return Err(SystemError::EINVAL);
|
||||
} else {
|
||||
// 禁用中断,防止在这段期间发生调度,造成死锁
|
||||
cli();
|
||||
timeout += unsafe { TIMER_JIFFIES } as i64;
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
|
||||
timeout += TIMER_JIFFIES.load(Ordering::SeqCst) as i64;
|
||||
let timer = Timer::new(WakeUpHelper::new(current_pcb()), timeout as u64);
|
||||
timer.activate();
|
||||
current_pcb().state &= (!PROC_RUNNING) as u64;
|
||||
sti();
|
||||
|
||||
drop(irq_guard);
|
||||
|
||||
sched();
|
||||
let time_remaining: i64 = timeout - unsafe { TIMER_JIFFIES } as i64;
|
||||
let time_remaining: i64 = timeout - TIMER_JIFFIES.load(Ordering::SeqCst) as i64;
|
||||
if time_remaining >= 0 {
|
||||
// 被提前唤醒,返回剩余时间
|
||||
return Ok(time_remaining);
|
||||
@ -270,21 +288,22 @@ pub fn timer_get_first_expire() -> Result<u64, SystemError> {
|
||||
}
|
||||
|
||||
pub fn update_timer_jiffies(add_jiffies: u64) -> u64 {
|
||||
unsafe { TIMER_JIFFIES += add_jiffies };
|
||||
return unsafe { TIMER_JIFFIES };
|
||||
let prev = TIMER_JIFFIES.fetch_add(add_jiffies, Ordering::SeqCst);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
update_wall_time();
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
return prev + add_jiffies;
|
||||
}
|
||||
|
||||
pub fn clock() -> u64 {
|
||||
return unsafe { TIMER_JIFFIES };
|
||||
return TIMER_JIFFIES.load(Ordering::SeqCst);
|
||||
}
|
||||
// ====== 重构完成后请删掉extern C ======
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_clock() -> u64 {
|
||||
clock()
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sys_clock(_regs: *const pt_regs) -> u64 {
|
||||
clock()
|
||||
}
|
||||
|
||||
// ====== 以下为给C提供的接口 ======
|
||||
#[no_mangle]
|
||||
|
25
user/apps/test_gettimeofday/Makefile
Normal file
25
user/apps/test_gettimeofday/Makefile
Normal file
@ -0,0 +1,25 @@
|
||||
CC=$(DragonOS_GCC)/x86_64-elf-gcc
|
||||
LD=ld
|
||||
OBJCOPY=objcopy
|
||||
# 修改这里,把它改为你的relibc的sysroot路径
|
||||
RELIBC_OPT=$(DADK_BUILD_CACHE_DIR_RELIBC_0_1_0)
|
||||
CFLAGS=-I $(RELIBC_OPT)/include
|
||||
|
||||
tmp_output_dir=$(ROOT_PATH)/bin/tmp/user
|
||||
output_dir=$(DADK_BUILD_CACHE_DIR_TEST_GETTIMEOFDAY_0_1_0)
|
||||
|
||||
LIBC_OBJS:=$(shell find $(RELIBC_OPT)/lib -name "*.o" | sort )
|
||||
LIBC_OBJS+=$(RELIBC_OPT)/lib/libc.a
|
||||
|
||||
all: main.o
|
||||
mkdir -p $(tmp_output_dir)
|
||||
|
||||
$(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_gettimeofday $(shell find . -name "*.o") $(LIBC_OBJS) -T link.lds
|
||||
|
||||
$(OBJCOPY) -I elf64-x86-64 -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/test_gettimeofday $(output_dir)/test_gettimeofday.elf
|
||||
mv $(output_dir)/test_gettimeofday.elf $(output_dir)/test_gettimeofday
|
||||
main.o: main.c
|
||||
$(CC) $(CFLAGS) -c main.c -o main.o
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
239
user/apps/test_gettimeofday/link.lds
Normal file
239
user/apps/test_gettimeofday/link.lds
Normal file
@ -0,0 +1,239 @@
|
||||
/* Script for -z combreloc */
|
||||
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||
Copying and distribution of this script, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. */
|
||||
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
|
||||
"elf64-x86-64")
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||
.hash : { *(.hash) }
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rela.dyn :
|
||||
{
|
||||
*(.rela.init)
|
||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||
*(.rela.fini)
|
||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||
*(.rela.ctors)
|
||||
*(.rela.dtors)
|
||||
*(.rela.got)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||
*(.rela.ifunc)
|
||||
}
|
||||
.rela.plt :
|
||||
{
|
||||
*(.rela.plt)
|
||||
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||
*(.rela.iplt)
|
||||
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||
}
|
||||
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||
.init :
|
||||
{
|
||||
KEEP (*(SORT_NONE(.init)))
|
||||
}
|
||||
.plt : { *(.plt) *(.iplt) }
|
||||
.plt.got : { *(.plt.got) }
|
||||
.plt.sec : { *(.plt.sec) }
|
||||
.text :
|
||||
{
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.hot .text.hot.*)
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
/* .gnu.warning sections are handled specially by elf.em. */
|
||||
*(.gnu.warning)
|
||||
}
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(SORT_NONE(.fini)))
|
||||
}
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||
/* Exception handling */
|
||||
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||
/* Thread Local Storage sections */
|
||||
.tdata :
|
||||
{
|
||||
PROVIDE_HIDDEN (__tdata_start = .);
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
}
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
}
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP (*(.jcr)) }
|
||||
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
.got : { *(.got) *(.igot) }
|
||||
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||
.data :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
_edata = .; PROVIDE (edata = .);
|
||||
. = .;
|
||||
__bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
/* Align here to ensure that the .bss section occupies space up to
|
||||
_end. Align after .bss to ensure correct alignment even if the
|
||||
.bss section disappears because there are no input sections.
|
||||
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||
pad the .data section. */
|
||||
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||
}
|
||||
.lbss :
|
||||
{
|
||||
*(.dynlbss)
|
||||
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||
*(LARGE_COMMON)
|
||||
}
|
||||
. = ALIGN(64 / 8);
|
||||
. = SEGMENT_START("ldata-segment", .);
|
||||
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||
{
|
||||
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||
}
|
||||
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||
{
|
||||
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||
}
|
||||
. = ALIGN(64 / 8);
|
||||
_end = .; PROVIDE (end = .);
|
||||
. = DATA_SEGMENT_END (.);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* DWARF 3 */
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
/* DWARF Extension. */
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
|
||||
}
|
25
user/apps/test_gettimeofday/main.c
Normal file
25
user/apps/test_gettimeofday/main.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
// #include <sleep.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
struct timeval *tv = malloc(sizeof(struct timeval));
|
||||
// struct timezone *tz = malloc(sizeof(struct timezone));
|
||||
// for (int i = 0; i < 15; i++)
|
||||
// {
|
||||
// gettimeofday(tv, NULL);
|
||||
// printf("%ld.%06ld\n", tv->tv_sec, tv->tv_usec);
|
||||
// for (int i = 0; i < 10; i++)
|
||||
// {
|
||||
// usleep(500000);
|
||||
// }
|
||||
// }
|
||||
gettimeofday(tv, NULL);
|
||||
printf("tv = %ld.%06ld\n", tv->tv_sec, tv->tv_usec);
|
||||
// printf("tz_minuteswest = %d,tz_dsttime = %d", (*tz).tz_minuteswest, (*tz).tz_dsttime);
|
||||
return 0;
|
||||
}
|
28
user/dadk/config/test_gettimeofday-0.1.0.dadk
Normal file
28
user/dadk/config/test_gettimeofday-0.1.0.dadk
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "test_gettimeofday",
|
||||
"version": "0.1.0",
|
||||
"description": "一个用来测试gettimeofday能够正常运行的app",
|
||||
"task_type": {
|
||||
"BuildFromSource": {
|
||||
"Local": {
|
||||
"path": "apps/test_gettimeofday"
|
||||
}
|
||||
}
|
||||
},
|
||||
"depends": [
|
||||
{
|
||||
"name": "relibc",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"build_command": "make"
|
||||
},
|
||||
"install": {
|
||||
"in_dragonos_path": "/bin"
|
||||
},
|
||||
"clean": {
|
||||
"clean_command": "make clean"
|
||||
},
|
||||
"envs": []
|
||||
}
|
Reference in New Issue
Block a user