mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-19 17:26: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
|
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]
|
#[inline]
|
||||||
pub fn local_irq_save(flags: &mut u64) {
|
pub fn local_irq_save() -> usize {
|
||||||
|
let x: usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("pushfq", "pop rax", "mov rax, {0}", "cli", out(reg)(*flags),);
|
asm!("pushfq ; pop {} ; cli", out(reg) x, options(nostack));
|
||||||
}
|
}
|
||||||
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn local_irq_restore(flags: &u64) {
|
// 恢复先前保存的rflags的值x
|
||||||
let x = unsafe { read_volatile(flags) };
|
pub fn local_irq_restore(x: usize) {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("push r15",
|
asm!("push {} ; popfq", in(reg) x, options(nostack));
|
||||||
"popfq", in("r15")(x));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,7 @@ impl FpState {
|
|||||||
/// @brief 从用户态进入内核时,保存浮点寄存器,并关闭浮点功能
|
/// @brief 从用户态进入内核时,保存浮点寄存器,并关闭浮点功能
|
||||||
pub fn fp_state_save(pcb: &mut process_control_block) {
|
pub fn fp_state_save(pcb: &mut process_control_block) {
|
||||||
// 该过程中不允许中断
|
// 该过程中不允许中断
|
||||||
let mut rflags: u64 = 0;
|
let rflags = local_irq_save();
|
||||||
local_irq_save(&mut rflags);
|
|
||||||
|
|
||||||
let fp: &mut FpState = if pcb.fp_state == null_mut() {
|
let fp: &mut FpState = if pcb.fp_state == null_mut() {
|
||||||
let f = Box::leak(Box::new(FpState::default()));
|
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" */
|
"mov cr4, rax" */
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
local_irq_restore(&rflags);
|
local_irq_restore(rflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief 从内核态返回用户态时,恢复浮点寄存器,并开启浮点功能
|
/// @brief 从内核态返回用户态时,恢复浮点寄存器,并开启浮点功能
|
||||||
pub fn fp_state_restore(pcb: &mut process_control_block) {
|
pub fn fp_state_restore(pcb: &mut process_control_block) {
|
||||||
// 该过程中不允许中断
|
// 该过程中不允许中断
|
||||||
let mut rflags: u64 = 0;
|
let rflags = local_irq_save();
|
||||||
local_irq_save(&mut rflags);
|
|
||||||
|
|
||||||
if pcb.fp_state == null_mut() {
|
if pcb.fp_state == null_mut() {
|
||||||
panic!("fp_state_restore: fp_state is null. pid={}", pcb.pid);
|
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.restore();
|
||||||
fp.clear();
|
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 {
|
unsafe fn save_and_disable_irq() -> IrqFlagsGuard {
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
let mut rflags: u64 = 0;
|
let rflags = local_irq_save() as u64;
|
||||||
local_irq_save(&mut rflags);
|
|
||||||
let flags = IrqFlags::new(rflags);
|
let flags = IrqFlags::new(rflags);
|
||||||
let guard = IrqFlagsGuard::new(flags);
|
let guard = IrqFlagsGuard::new(flags);
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
@ -58,7 +57,7 @@ impl InterruptArch for X86_64InterruptArch {
|
|||||||
|
|
||||||
unsafe fn restore_irq(flags: IrqFlags) {
|
unsafe fn restore_irq(flags: IrqFlags) {
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
local_irq_restore(&flags.flags());
|
local_irq_restore(flags.flags() as usize);
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,4 +66,11 @@ extern struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM];
|
|||||||
*
|
*
|
||||||
* @return uint32_t 当前cpu核心晶振频率
|
* @return uint32_t 当前cpu核心晶振频率
|
||||||
*/
|
*/
|
||||||
uint32_t cpu_get_core_crysral_freq();
|
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("[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))));
|
// 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");
|
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()
|
int HPET_init()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::interrupt::{cli, sti},
|
arch::CurrentIrqArch,
|
||||||
|
exception::InterruptArch,
|
||||||
include::bindings::bindings::{io_in8, io_out8},
|
include::bindings::bindings::{io_in8, io_out8},
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
};
|
};
|
||||||
@ -33,7 +34,7 @@ impl RtcTime {
|
|||||||
///@return int 成功则为0
|
///@return int 成功则为0
|
||||||
pub fn get(&mut self) -> Result<i32, SystemError> {
|
pub fn get(&mut self) -> Result<i32, SystemError> {
|
||||||
// 为防止中断请求打断该过程,需要先关中断
|
// 为防止中断请求打断该过程,需要先关中断
|
||||||
cli();
|
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||||
//0x0B
|
//0x0B
|
||||||
let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B
|
let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B
|
||||||
let is_24h: bool = if (status_register_b & 0x02) != 0 {
|
let is_24h: bool = if (status_register_b & 0x02) != 0 {
|
||||||
@ -81,7 +82,7 @@ impl RtcTime {
|
|||||||
self.hour = ((self.hour & 0x7f) + 12) % 24;
|
self.hour = ((self.hour & 0x7f) + 12) % 24;
|
||||||
} // 将十二小时制转为24小时
|
} // 将十二小时制转为24小时
|
||||||
|
|
||||||
sti();
|
drop(irq_guard);
|
||||||
|
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
@ -225,15 +225,14 @@ impl Softirq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
|
pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
|
||||||
let mut flags = 0;
|
let flags = local_irq_save();
|
||||||
local_irq_save(&mut flags);
|
|
||||||
let processor_id = smp_get_processor_id() as usize;
|
let processor_id = smp_get_processor_id() as usize;
|
||||||
|
|
||||||
cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
|
cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
local_irq_restore(&flags);
|
local_irq_restore(flags);
|
||||||
// kdebug!("raise_softirq exited");
|
// kdebug!("raise_softirq exited");
|
||||||
}
|
}
|
||||||
pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
|
pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
|
||||||
|
@ -46,4 +46,5 @@
|
|||||||
#include <process/process.h>
|
#include <process/process.h>
|
||||||
#include <sched/sched.h>
|
#include <sched/sched.h>
|
||||||
#include <smp/smp.h>
|
#include <smp/smp.h>
|
||||||
|
#include <time/clocksource.h>
|
||||||
#include <time/sleep.h>
|
#include <time/sleep.h>
|
||||||
|
@ -120,3 +120,12 @@ uint32_t cpu_get_core_crysral_freq()
|
|||||||
|
|
||||||
return c;
|
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中,关闭中断,并对自旋锁加锁
|
/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) {
|
pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) {
|
||||||
local_irq_save(flags);
|
*flags = local_irq_save() as u64;
|
||||||
unsafe {
|
unsafe {
|
||||||
spin_lock(lock);
|
spin_lock(lock);
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) {
|
|||||||
spin_unlock(lock);
|
spin_unlock(lock);
|
||||||
}
|
}
|
||||||
// kdebug!("123");
|
// kdebug!("123");
|
||||||
local_irq_restore(flags);
|
local_irq_restore(*flags as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 判断一个自旋锁是否已经被加锁
|
/// 判断一个自旋锁是否已经被加锁
|
||||||
@ -130,14 +130,14 @@ impl RawSpinlock {
|
|||||||
|
|
||||||
/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||||
pub fn lock_irqsave(&self, flags: &mut u64) {
|
pub fn lock_irqsave(&self, flags: &mut u64) {
|
||||||
local_irq_save(flags);
|
*flags = local_irq_save() as u64;
|
||||||
self.lock();
|
self.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief 恢复rflags以及中断状态并解锁自旋锁
|
/// @brief 恢复rflags以及中断状态并解锁自旋锁
|
||||||
pub fn unlock_irqrestore(&self, flags: &u64) {
|
pub fn unlock_irqrestore(&self, flags: &u64) {
|
||||||
self.unlock();
|
self.unlock();
|
||||||
local_irq_restore(flags);
|
local_irq_restore(*flags as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief 尝试保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
/// @brief 尝试保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||||
@ -145,11 +145,11 @@ impl RawSpinlock {
|
|||||||
/// 加锁失败->false
|
/// 加锁失败->false
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn try_lock_irqsave(&self, flags: &mut u64) -> bool {
|
pub fn try_lock_irqsave(&self, flags: &mut u64) -> bool {
|
||||||
local_irq_save(flags);
|
*flags = local_irq_save() as u64;
|
||||||
if self.try_lock() {
|
if self.try_lock() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
local_irq_restore(flags);
|
local_irq_restore(*flags as usize);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,8 @@ void reload_gdt()
|
|||||||
gdtp.size = bsp_gdt_size - 1;
|
gdtp.size = bsp_gdt_size - 1;
|
||||||
gdtp.gdt_vaddr = (ul)phys_2_virt((ul)&GDT_Table);
|
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()
|
void reload_idt()
|
||||||
@ -62,7 +63,8 @@ void reload_idt()
|
|||||||
// kdebug("gdtvaddr=%#018lx", p.gdt_vaddr);
|
// kdebug("gdtvaddr=%#018lx", p.gdt_vaddr);
|
||||||
// kdebug("gdt size=%d", p.size);
|
// 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->cpu_id = 0;
|
||||||
current_pcb->preempt_count = 0;
|
current_pcb->preempt_count = 0;
|
||||||
// 先初始化系统调用模块
|
|
||||||
syscall_init();
|
syscall_init();
|
||||||
|
|
||||||
io_mfence();
|
io_mfence();
|
||||||
// 再初始化进程模块。顺序不能调转
|
|
||||||
// sched_init();
|
rs_timekeeping_init();
|
||||||
io_mfence();
|
io_mfence();
|
||||||
|
|
||||||
rs_timer_init();
|
rs_timer_init();
|
||||||
|
io_mfence();
|
||||||
|
|
||||||
|
rs_jiffies_init();
|
||||||
|
io_mfence();
|
||||||
|
|
||||||
|
rs_clocksource_boot_finish();
|
||||||
// 这里必须加内存屏障,否则会出错
|
// 这里必须加内存屏障,否则会出错
|
||||||
io_mfence();
|
io_mfence();
|
||||||
smp_init();
|
smp_init();
|
||||||
@ -140,7 +148,7 @@ void system_initialize()
|
|||||||
|
|
||||||
vfs_init();
|
vfs_init();
|
||||||
rs_tty_init();
|
rs_tty_init();
|
||||||
|
|
||||||
cpu_init();
|
cpu_init();
|
||||||
ps2_keyboard_init();
|
ps2_keyboard_init();
|
||||||
// tty_init();
|
// tty_init();
|
||||||
@ -160,7 +168,7 @@ void system_initialize()
|
|||||||
io_mfence();
|
io_mfence();
|
||||||
// current_pcb->preempt_count = 0;
|
// current_pcb->preempt_count = 0;
|
||||||
// kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq());
|
// kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq());
|
||||||
|
|
||||||
process_init();
|
process_init();
|
||||||
// 启用double buffer
|
// 启用double buffer
|
||||||
// scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread
|
// scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread
|
||||||
@ -173,7 +181,7 @@ void system_initialize()
|
|||||||
|
|
||||||
apic_timer_init();
|
apic_timer_init();
|
||||||
io_mfence();
|
io_mfence();
|
||||||
|
|
||||||
// 这里不能删除,否则在O1会报错
|
// 这里不能删除,否则在O1会报错
|
||||||
// while (1)
|
// while (1)
|
||||||
// pause();
|
// pause();
|
||||||
|
@ -15,13 +15,16 @@ use super::socket::{SOCKET_SET, SOCKET_WAITQUEUE};
|
|||||||
/// The network poll function, which will be called by timer.
|
/// The network poll function, which will be called by timer.
|
||||||
///
|
///
|
||||||
/// The main purpose of this function is to poll all network interfaces.
|
/// The main purpose of this function is to poll all network interfaces.
|
||||||
struct NetWorkPollFunc();
|
#[derive(Debug)]
|
||||||
|
struct NetWorkPollFunc;
|
||||||
|
|
||||||
impl TimerFunction for NetWorkPollFunc {
|
impl TimerFunction for NetWorkPollFunc {
|
||||||
fn run(&mut self) {
|
fn run(&mut self) -> Result<(), SystemError> {
|
||||||
poll_ifaces_try_lock(10).ok();
|
poll_ifaces_try_lock(10).ok();
|
||||||
let next_time = next_n_ms_timer_jiffies(10);
|
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();
|
timer.activate();
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +32,7 @@ pub fn net_init() -> Result<(), SystemError> {
|
|||||||
dhcp_query()?;
|
dhcp_query()?;
|
||||||
// Init poll timer function
|
// Init poll timer function
|
||||||
let next_time = next_n_ms_timer_jiffies(5);
|
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();
|
timer.activate();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -859,7 +859,8 @@ void process_exit_thread(struct process_control_block *pcb)
|
|||||||
int process_release_pcb(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结构体
|
if ((pcb->flags & PF_KTHREAD)) // 释放内核线程的worker private结构体
|
||||||
free_kthread_struct(pcb);
|
free_kthread_struct(pcb);
|
||||||
|
|
||||||
|
@ -16,7 +16,10 @@ use crate::{
|
|||||||
io::SeekFrom,
|
io::SeekFrom,
|
||||||
kinfo,
|
kinfo,
|
||||||
net::syscall::SockAddr,
|
net::syscall::SockAddr,
|
||||||
time::TimeSpec,
|
time::{
|
||||||
|
syscall::{PosixTimeZone, PosixTimeval, SYS_TIMEZONE},
|
||||||
|
TimeSpec,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
@ -354,6 +357,7 @@ pub const SYS_ACCEPT: usize = 40;
|
|||||||
|
|
||||||
pub const SYS_GETSOCKNAME: usize = 41;
|
pub const SYS_GETSOCKNAME: usize = 41;
|
||||||
pub const SYS_GETPEERNAME: usize = 42;
|
pub const SYS_GETPEERNAME: usize = 42;
|
||||||
|
pub const SYS_GETTIMEOFDAY: usize = 43;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Syscall;
|
pub struct Syscall;
|
||||||
@ -867,6 +871,43 @@ impl Syscall {
|
|||||||
SYS_GETPEERNAME => {
|
SYS_GETPEERNAME => {
|
||||||
Self::getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32)
|
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),
|
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,3 +53,6 @@
|
|||||||
#define SYS_ACCEPT 40 // 接受一个socket连接
|
#define SYS_ACCEPT 40 // 接受一个socket连接
|
||||||
#define SYS_GETSOCKNAME 41 // 获取socket的名字
|
#define SYS_GETSOCKNAME 41 // 获取socket的名字
|
||||||
#define SYS_GETPEERNAME 42 // 获取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;
|
use self::timekeep::ktime_get_real_ns;
|
||||||
|
|
||||||
|
pub mod clocksource;
|
||||||
|
pub mod jiffies;
|
||||||
pub mod sleep;
|
pub mod sleep;
|
||||||
pub mod syscall;
|
pub mod syscall;
|
||||||
|
pub mod timeconv;
|
||||||
pub mod timekeep;
|
pub mod timekeep;
|
||||||
|
pub mod timekeeping;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
||||||
/* Time structures. (Partitially taken from smoltcp)
|
/* Time structures. (Partitially taken from smoltcp)
|
||||||
|
|
||||||
The `time` module contains structures used to represent both
|
The `time` module contains structures used to represent both
|
||||||
@ -18,6 +21,20 @@ absolute and relative time.
|
|||||||
[Instant]: struct.Instant.html
|
[Instant]: struct.Instant.html
|
||||||
[Duration]: struct.Duration.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标准。
|
/// 表示时间的结构体,符合POSIX标准。
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[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::{
|
use crate::{
|
||||||
|
kdebug,
|
||||||
syscall::{Syscall, SystemError},
|
syscall::{Syscall, SystemError},
|
||||||
time::{sleep::nanosleep, TimeSpec},
|
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 {
|
impl Syscall {
|
||||||
/// @brief 休眠指定时间(单位:纳秒)(提供给C的接口)
|
/// @brief 休眠指定时间(单位:纳秒)(提供给C的接口)
|
||||||
///
|
///
|
||||||
@ -44,4 +76,22 @@ impl Syscall {
|
|||||||
pub fn clock() -> Result<usize, SystemError> {
|
pub fn clock() -> Result<usize, SystemError> {
|
||||||
return Ok(super::timer::clock() as usize);
|
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 <common/glib.h>
|
||||||
#include <driver/timers/HPET/HPET.h>
|
#include <driver/timers/HPET/HPET.h>
|
||||||
|
#include <common/kthread.h>
|
||||||
|
|
||||||
// 定义LONG_MAX为最大超时时间 - 允许负数
|
// 定义LONG_MAX为最大超时时间 - 允许负数
|
||||||
#define MAX_TIMEOUT (int64_t)((1ul << 63) - 1)
|
#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::{
|
use alloc::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
@ -7,31 +11,33 @@ use alloc::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{
|
arch::{asm::current::current_pcb, sched::sched, CurrentIrqArch},
|
||||||
asm::current::current_pcb,
|
exception::{
|
||||||
interrupt::{cli, sti},
|
softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
|
||||||
sched::sched,
|
InterruptArch,
|
||||||
},
|
},
|
||||||
exception::softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
|
include::bindings::bindings::{process_control_block, process_wakeup, PROC_RUNNING},
|
||||||
include::bindings::bindings::{process_control_block, process_wakeup, pt_regs, PROC_RUNNING},
|
|
||||||
kdebug, kerror,
|
kdebug, kerror,
|
||||||
libs::spinlock::SpinLock,
|
libs::spinlock::SpinLock,
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::timekeeping::update_wall_time;
|
||||||
|
|
||||||
const MAX_TIMEOUT: i64 = i64::MAX;
|
const MAX_TIMEOUT: i64 = i64::MAX;
|
||||||
const TIMER_RUN_CYCLE_THRESHOLD: usize = 20;
|
const TIMER_RUN_CYCLE_THRESHOLD: usize = 20;
|
||||||
static mut TIMER_JIFFIES: u64 = 0;
|
static TIMER_JIFFIES: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref TIMER_LIST: SpinLock<LinkedList<Arc<Timer>>> = SpinLock::new(LinkedList::new());
|
pub static ref TIMER_LIST: SpinLock<LinkedList<Arc<Timer>>> = SpinLock::new(LinkedList::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 定时器要执行的函数的特征
|
/// 定时器要执行的函数的特征
|
||||||
pub trait TimerFunction: Send + Sync {
|
pub trait TimerFunction: Send + Sync + Debug {
|
||||||
fn run(&mut self);
|
fn run(&mut self) -> Result<(), SystemError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
/// WakeUpHelper函数对应的结构体
|
/// WakeUpHelper函数对应的结构体
|
||||||
pub struct WakeUpHelper {
|
pub struct WakeUpHelper {
|
||||||
pcb: &'static mut process_control_block,
|
pcb: &'static mut process_control_block,
|
||||||
@ -44,13 +50,15 @@ impl WakeUpHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TimerFunction for WakeUpHelper {
|
impl TimerFunction for WakeUpHelper {
|
||||||
fn run(&mut self) {
|
fn run(&mut self) -> Result<(), SystemError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
process_wakeup(self.pcb);
|
process_wakeup(self.pcb);
|
||||||
}
|
}
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Timer(SpinLock<InnerTimer>);
|
pub struct Timer(SpinLock<InnerTimer>);
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
@ -97,6 +105,7 @@ impl Timer {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut temp_list: LinkedList<Arc<Timer>> = timer_list.split_off(split_pos);
|
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.push_back(inner_guard.self_ref.upgrade().unwrap());
|
||||||
timer_list.append(&mut temp_list);
|
timer_list.append(&mut temp_list);
|
||||||
@ -106,11 +115,18 @@ impl Timer {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn run(&self) {
|
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 struct InnerTimer {
|
||||||
/// 定时器结束时刻
|
/// 定时器结束时刻
|
||||||
pub expire_jiffies: u64,
|
pub expire_jiffies: u64,
|
||||||
@ -179,7 +195,7 @@ impl SoftirqVec for DoTimerSoftirq {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let timer_list_front_guard = timer_list_front_guard.unwrap();
|
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);
|
drop(timer_list_front_guard);
|
||||||
timer_list.push_front(timer_list_front);
|
timer_list.push_front(timer_list_front);
|
||||||
break;
|
break;
|
||||||
@ -205,11 +221,11 @@ pub fn timer_init() {
|
|||||||
|
|
||||||
/// 计算接下来n毫秒对应的定时器时间片
|
/// 计算接下来n毫秒对应的定时器时间片
|
||||||
pub fn next_n_ms_timer_jiffies(expire_ms: u64) -> u64 {
|
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微秒对应的定时器时间片
|
/// 计算接下来n微秒对应的定时器时间片
|
||||||
pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64 {
|
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
|
/// @brief 让pcb休眠timeout个jiffies
|
||||||
@ -229,15 +245,17 @@ pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
|
|||||||
return Err(SystemError::EINVAL);
|
return Err(SystemError::EINVAL);
|
||||||
} else {
|
} else {
|
||||||
// 禁用中断,防止在这段期间发生调度,造成死锁
|
// 禁用中断,防止在这段期间发生调度,造成死锁
|
||||||
cli();
|
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||||
timeout += unsafe { TIMER_JIFFIES } as i64;
|
|
||||||
|
timeout += TIMER_JIFFIES.load(Ordering::SeqCst) as i64;
|
||||||
let timer = Timer::new(WakeUpHelper::new(current_pcb()), timeout as u64);
|
let timer = Timer::new(WakeUpHelper::new(current_pcb()), timeout as u64);
|
||||||
timer.activate();
|
timer.activate();
|
||||||
current_pcb().state &= (!PROC_RUNNING) as u64;
|
current_pcb().state &= (!PROC_RUNNING) as u64;
|
||||||
sti();
|
|
||||||
|
drop(irq_guard);
|
||||||
|
|
||||||
sched();
|
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 {
|
if time_remaining >= 0 {
|
||||||
// 被提前唤醒,返回剩余时间
|
// 被提前唤醒,返回剩余时间
|
||||||
return Ok(time_remaining);
|
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 {
|
pub fn update_timer_jiffies(add_jiffies: u64) -> u64 {
|
||||||
unsafe { TIMER_JIFFIES += add_jiffies };
|
let prev = TIMER_JIFFIES.fetch_add(add_jiffies, Ordering::SeqCst);
|
||||||
return unsafe { TIMER_JIFFIES };
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
update_wall_time();
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
return prev + add_jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clock() -> u64 {
|
pub fn clock() -> u64 {
|
||||||
return unsafe { TIMER_JIFFIES };
|
return TIMER_JIFFIES.load(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
// ====== 重构完成后请删掉extern C ======
|
// ====== 重构完成后请删掉extern C ======
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rs_clock() -> u64 {
|
pub extern "C" fn rs_clock() -> u64 {
|
||||||
clock()
|
clock()
|
||||||
}
|
}
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn sys_clock(_regs: *const pt_regs) -> u64 {
|
|
||||||
clock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====== 以下为给C提供的接口 ======
|
// ====== 以下为给C提供的接口 ======
|
||||||
#[no_mangle]
|
#[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;
|
||||||
|
}
|
@ -27,4 +27,4 @@
|
|||||||
"value": "x86_64-unknown-dragonos"
|
"value": "x86_64-unknown-dragonos"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
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