mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
finish PIT Timer and add testcase
This commit is contained in:
parent
492022cbeb
commit
280591db66
@ -4,9 +4,13 @@ pub mod framebuffer;
|
||||
mod io_port;
|
||||
pub mod pci;
|
||||
pub mod serial;
|
||||
mod pic;
|
||||
|
||||
pub use pic::{TimerCallback, TIMER_FREQ};
|
||||
pub(crate) use pic::{add_timeout_list,TICK};
|
||||
pub use self::io_port::IoPort;
|
||||
|
||||
pub(crate) fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) {
|
||||
framebuffer::init(framebuffer);
|
||||
pic::init();
|
||||
}
|
||||
|
182
src/kxos-frame/src/device/pic.rs
Normal file
182
src/kxos-frame/src/device/pic.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use crate::cell::Cell;
|
||||
use crate::x86_64_util::out8;
|
||||
use crate::{IrqAllocateHandle, TrapFrame};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{boxed::Box, collections::BinaryHeap};
|
||||
use core::any::Any;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
|
||||
const MASTER_CMD: u16 = 0x20;
|
||||
const MASTER_DATA: u16 = MASTER_CMD + 1;
|
||||
const SLAVE_CMD: u16 = 0xA0;
|
||||
const SLAVE_DATA: u16 = SLAVE_CMD + 1;
|
||||
|
||||
const TIMER_RATE: u32 = 1193182;
|
||||
/// This value represent the base timer frequency in Hz
|
||||
pub const TIMER_FREQ: u64 = 100;
|
||||
const TIMER_PERIOD_IO_PORT: u16 = 0x40;
|
||||
const TIMER_MODE_IO_PORT: u16 = 0x43;
|
||||
const TIMER_SQUARE_WAVE: u8 = 0x36;
|
||||
|
||||
const TIMER_IRQ_NUM: u8 = 32;
|
||||
|
||||
pub static mut TICK: u64 = 0;
|
||||
|
||||
lazy_static! {
|
||||
static ref TIMER_IRQ: Mutex<IrqAllocateHandle> = Mutex::new(
|
||||
crate::trap::allocate_target_irq(TIMER_IRQ_NUM).expect("Timer irq Allocate error")
|
||||
);
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
// Start initialization
|
||||
out8(MASTER_CMD, 0x11);
|
||||
out8(SLAVE_CMD, 0x11);
|
||||
|
||||
// Set offsets
|
||||
out8(MASTER_DATA, 0x20);
|
||||
out8(SLAVE_DATA, 0x28);
|
||||
|
||||
// Set up cascade
|
||||
out8(MASTER_DATA, 4);
|
||||
out8(SLAVE_DATA, 2);
|
||||
|
||||
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
|
||||
out8(MASTER_DATA, 1);
|
||||
out8(SLAVE_DATA, 1);
|
||||
|
||||
// Unmask interrupts
|
||||
out8(MASTER_DATA, 0);
|
||||
out8(SLAVE_DATA, 0);
|
||||
|
||||
// Ack remaining interrupts
|
||||
out8(MASTER_CMD, 0x20);
|
||||
out8(SLAVE_CMD, 0x20);
|
||||
|
||||
// Initialize timer.
|
||||
let cycle = TIMER_RATE / TIMER_FREQ as u32; // 1ms per interrupt.
|
||||
out8(TIMER_MODE_IO_PORT, TIMER_SQUARE_WAVE);
|
||||
out8(TIMER_PERIOD_IO_PORT, (cycle & 0xFF) as _);
|
||||
out8(TIMER_PERIOD_IO_PORT, (cycle >> 8) as _);
|
||||
TIMER_IRQ.lock().on_active(timer_callback);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ack() {
|
||||
out8(MASTER_CMD, 0x20);
|
||||
}
|
||||
|
||||
fn timer_callback(trap_frame: &TrapFrame) {
|
||||
// FIXME: disable and enable interupt will cause infinity loop
|
||||
// x86_64_util::disable_interrupts();
|
||||
ack();
|
||||
let current_ms;
|
||||
unsafe {
|
||||
current_ms = TICK;
|
||||
TICK += 1;
|
||||
}
|
||||
let timeout_list = TIMEOUT_LIST.get();
|
||||
let mut callbacks : Vec<Arc<TimerCallback>>= Vec::new();
|
||||
while let Some(t) = timeout_list.peek() {
|
||||
if t.expire_ms <= current_ms {
|
||||
callbacks.push(timeout_list.pop().unwrap());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for callback in callbacks{
|
||||
if callback.is_enable(){
|
||||
callback.callback.call((&callback,));
|
||||
}
|
||||
}
|
||||
// x86_64_util::enable_interrupts();
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref TIMEOUT_LIST: Cell<BinaryHeap<Arc<TimerCallback>>> = Cell::new(BinaryHeap::new()) ;
|
||||
}
|
||||
|
||||
pub struct TimerCallback {
|
||||
expire_ms: u64,
|
||||
data: Arc<dyn Any + Send + Sync>,
|
||||
callback: Box<dyn Fn(&TimerCallback) + Send + Sync>,
|
||||
enable: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TimerCallback {
|
||||
fn new(
|
||||
timeout_ms: u64,
|
||||
data: Arc<dyn Any + Send + Sync>,
|
||||
callback: Box<dyn Fn(&TimerCallback) + Send + Sync>,
|
||||
) -> Self {
|
||||
Self {
|
||||
expire_ms: timeout_ms,
|
||||
data,
|
||||
callback,
|
||||
enable:Cell::new(true),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &Arc<dyn Any + Send + Sync> {
|
||||
&self.data
|
||||
}
|
||||
|
||||
/// disable this timeout
|
||||
pub fn disable(&self){
|
||||
*self.enable.get() = false;
|
||||
}
|
||||
|
||||
/// enable this timeout
|
||||
pub fn enable(&self){
|
||||
*self.enable.get() = true;
|
||||
}
|
||||
|
||||
pub fn is_enable(&self) -> bool{
|
||||
*self.enable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PartialEq for TimerCallback {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.expire_ms == other.expire_ms
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for TimerCallback {}
|
||||
|
||||
impl PartialOrd for TimerCallback {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TimerCallback {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
self.expire_ms.cmp(&other.expire_ms).reverse()
|
||||
}
|
||||
}
|
||||
|
||||
/// add timeout task into timeout list, the frequency see const TIMER_FREQ
|
||||
///
|
||||
/// user should ensure that the callback function cannot take too much time
|
||||
///
|
||||
pub fn add_timeout_list<F, T>(timeout: u64, data: T, callback: F) -> Arc<TimerCallback>
|
||||
where
|
||||
F: Fn(&TimerCallback) + Send + Sync + 'static,
|
||||
T: Any + Send + Sync,
|
||||
|
||||
{
|
||||
unsafe {
|
||||
let timer_callback = TimerCallback::new(
|
||||
TICK + timeout,
|
||||
Arc::new(data),
|
||||
Box::new(callback),
|
||||
);
|
||||
let arc = Arc::new(timer_callback);
|
||||
TIMEOUT_LIST.get().push(arc.clone());
|
||||
arc
|
||||
}
|
||||
}
|
@ -62,10 +62,6 @@ pub use crate::serial_println as println;
|
||||
|
||||
pub fn init(boot_info: &'static mut BootInfo) {
|
||||
let siz = boot_info.framebuffer.as_ref().unwrap() as *const FrameBuffer as usize;
|
||||
device::init(boot_info.framebuffer.as_mut().unwrap());
|
||||
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
|
||||
trap::init();
|
||||
enable_common_cpu_features();
|
||||
let mut memory_init = false;
|
||||
// memory
|
||||
for region in boot_info.memory_regions.iter() {
|
||||
@ -84,13 +80,19 @@ pub fn init(boot_info: &'static mut BootInfo) {
|
||||
if !memory_init {
|
||||
panic!("memory init failed");
|
||||
}
|
||||
device::init(boot_info.framebuffer.as_mut().unwrap());
|
||||
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
|
||||
trap::init();
|
||||
enable_common_cpu_features();
|
||||
unsafe {
|
||||
for i in 0..256 {
|
||||
IRQ_CALLBACK_LIST.push(IrqLine::acquire(i as u8).on_active(general_handler))
|
||||
}
|
||||
}
|
||||
// uncomment below code to enable timer interrupt
|
||||
// x86_64_util::enable_interrupts_and_hlt();
|
||||
}
|
||||
fn general_handler(trap_frame: TrapFrame) {
|
||||
fn general_handler(trap_frame: &TrapFrame) {
|
||||
println!("{:#x?}", trap_frame);
|
||||
println!("rip = 0x{:x}", trap_frame.rip);
|
||||
println!("rsp = 0x{:x}", trap_frame.rsp);
|
||||
@ -113,7 +115,7 @@ where
|
||||
T: Fn(),
|
||||
{
|
||||
fn run(&self) {
|
||||
serial_print!("{}...\t", core::any::type_name::<T>());
|
||||
serial_print!("{}...\n", core::any::type_name::<T>());
|
||||
self();
|
||||
serial_println!("[ok]");
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Timer.
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{prelude::*, device::{TimerCallback, TICK,TIMER_FREQ}};
|
||||
use spin::Mutex;
|
||||
use core::time::Duration;
|
||||
|
||||
/// A timer invokes a callback function after a specified span of time elapsed.
|
||||
@ -11,33 +12,86 @@ use core::time::Duration;
|
||||
///
|
||||
/// Timers are one-shot. If the time is out, one has to set the timer again
|
||||
/// in order to trigger the callback again.
|
||||
pub struct Timer {}
|
||||
pub struct Timer {
|
||||
function: Arc<dyn Fn(Arc<Self>)+Send+Sync>,
|
||||
inner: Mutex<TimerInner>,
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct TimerInner{
|
||||
start_tick: u64,
|
||||
timeout_tick:u64,
|
||||
timer_callback:Option<Arc<TimerCallback>>,
|
||||
}
|
||||
|
||||
fn timer_callback(callback:&TimerCallback){
|
||||
let data = callback.data();
|
||||
if data.is::<Arc<Timer>>(){
|
||||
let timer = data.downcast_ref::<Arc<Timer>>().unwrap();
|
||||
timer.function.call((timer.clone(),));
|
||||
}else{
|
||||
panic!("the timer callback is not Timer structure");
|
||||
}
|
||||
}
|
||||
|
||||
const NANOS_DIVIDE : u64 = 1_000_000_000/TIMER_FREQ;
|
||||
|
||||
impl Timer {
|
||||
/// Creates a new instance, given a callback function.
|
||||
pub fn new<F>(f: F) -> Result<Self>
|
||||
pub fn new<F>(f: F) -> Result<Arc<Self>>
|
||||
where
|
||||
F: FnMut(&Self),
|
||||
F: Fn(Arc<Timer>) +Send+Sync+'static,
|
||||
{
|
||||
todo!()
|
||||
Ok(Arc::new(Self { function: Arc::new(f),inner:Mutex::new(TimerInner::default()) }))
|
||||
}
|
||||
|
||||
/// Set a timeout value.
|
||||
///
|
||||
/// If a timeout value is already set, the timeout value will be refreshed.
|
||||
pub fn set(&self, timeout: Duration) {
|
||||
todo!()
|
||||
///
|
||||
pub fn set(self : Arc<Self>, timeout: Duration) {
|
||||
let mut lock = self.inner.lock();
|
||||
match &lock.timer_callback{
|
||||
Some(callback) => {
|
||||
callback.disable();
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
let tick_count = timeout.as_secs()*TIMER_FREQ
|
||||
+ if timeout.subsec_nanos() !=0{(timeout.subsec_nanos() as u64 - 1)/NANOS_DIVIDE + 1} else {0};
|
||||
unsafe{
|
||||
lock.start_tick = TICK;
|
||||
lock.timeout_tick = TICK+tick_count;
|
||||
}
|
||||
lock.timer_callback = Some(crate::device::add_timeout_list(tick_count, self.clone(), timer_callback));
|
||||
|
||||
}
|
||||
|
||||
/// Returns the remaining timeout value.
|
||||
///
|
||||
/// If the timer is not set, then the remaining timeout value is zero.
|
||||
pub fn remain(&self) -> Duration {
|
||||
todo!()
|
||||
let lock = self.inner.lock();
|
||||
let tick_remain;
|
||||
unsafe{
|
||||
tick_remain = lock.timeout_tick as i64-TICK as i64;
|
||||
}
|
||||
if tick_remain<=0{
|
||||
Duration::new(0,0)
|
||||
}else{
|
||||
let second_count = tick_remain as u64/TIMER_FREQ;
|
||||
let remain_count = tick_remain as u64 % TIMER_FREQ;
|
||||
Duration::new(second_count,(remain_count * NANOS_DIVIDE) as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the timeout value.
|
||||
pub fn clear(&self) {
|
||||
todo!()
|
||||
let mut lock = self.inner.lock();
|
||||
if let Some(callback) = &lock.timer_callback{
|
||||
callback.disable();
|
||||
}
|
||||
lock.timeout_tick = 0;
|
||||
lock.start_tick = 0;
|
||||
lock.timer_callback = None;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use crate::task::{
|
||||
use super::{irq::IRQ_LIST, *};
|
||||
|
||||
#[no_mangle]
|
||||
pub(crate) extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize {
|
||||
pub(crate) extern "C" fn syscall_handler(f: &mut SyscallFrame) -> isize {
|
||||
let r = &f.caller;
|
||||
let current = Task::current();
|
||||
current.inner_exclusive_access().is_from_trap = false;
|
||||
@ -20,7 +20,7 @@ pub(crate) extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub(crate) extern "C" fn trap_handler(f: &'static mut TrapFrame) {
|
||||
pub(crate) extern "C" fn trap_handler(f: &mut TrapFrame) {
|
||||
if !is_from_kernel(f.cs) {
|
||||
let current = Task::current();
|
||||
current.inner_exclusive_access().is_from_trap = true;
|
||||
@ -37,11 +37,18 @@ pub(crate) extern "C" fn trap_handler(f: &'static mut TrapFrame) {
|
||||
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
|
||||
let callback_functions = irq_line.callback_list();
|
||||
for callback_function in callback_functions.iter() {
|
||||
callback_function.call(f.clone());
|
||||
callback_function.call(f);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("cannot handle kernel exception now");
|
||||
if is_cpu_fault(f){
|
||||
panic!("cannot handle kernel cpu fault now");
|
||||
}
|
||||
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
|
||||
let callback_functions = irq_line.callback_list();
|
||||
for callback_function in callback_functions.iter() {
|
||||
callback_function.call(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,14 @@ pub fn allocate_irq() -> Result<IrqAllocateHandle> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn allocate_target_irq(target_irq: u8) -> Result<IrqAllocateHandle> {
|
||||
if NOT_USING_IRQ.lock().get_target(target_irq as usize) {
|
||||
Ok(IrqAllocateHandle::new(target_irq))
|
||||
} else {
|
||||
Err(Error::NotEnoughResources)
|
||||
}
|
||||
}
|
||||
|
||||
/// The handle to a allocate irq number between [32,256), used in std and other parts in kxos
|
||||
///
|
||||
/// When the handle is dropped, all the callback in this will be unregistered automatically.
|
||||
@ -50,7 +58,7 @@ impl IrqAllocateHandle {
|
||||
/// For each IRQ line, multiple callbacks may be registered.
|
||||
pub fn on_active<F>(&mut self, callback: F)
|
||||
where
|
||||
F: Fn(TrapFrame) + Sync + Send + 'static,
|
||||
F: Fn(&TrapFrame) + Sync + Send + 'static,
|
||||
{
|
||||
self.callbacks.push(self.irq.on_active(callback))
|
||||
}
|
||||
@ -87,12 +95,12 @@ lazy_static! {
|
||||
}
|
||||
|
||||
pub struct CallbackElement {
|
||||
function: Box<dyn Fn(TrapFrame) + Send + Sync + 'static>,
|
||||
function: Box<dyn Fn(&TrapFrame) + Send + Sync + 'static>,
|
||||
id: usize,
|
||||
}
|
||||
|
||||
impl CallbackElement {
|
||||
pub fn call(&self, element: TrapFrame) {
|
||||
pub fn call(&self, element: &TrapFrame) {
|
||||
self.function.call((element,));
|
||||
}
|
||||
}
|
||||
@ -140,7 +148,7 @@ impl IrqLine {
|
||||
/// For each IRQ line, multiple callbacks may be registered.
|
||||
pub fn on_active<F>(&self, callback: F) -> IrqCallbackHandle
|
||||
where
|
||||
F: Fn(TrapFrame) + Sync + Send + 'static,
|
||||
F: Fn(&TrapFrame) + Sync + Send + 'static,
|
||||
{
|
||||
let allocate_id = ID_ALLOCATOR.lock().alloc();
|
||||
self.callback_list.lock().push(CallbackElement {
|
||||
|
@ -2,7 +2,7 @@ mod handler;
|
||||
mod irq;
|
||||
|
||||
pub use self::irq::{allocate_irq, IrqAllocateHandle};
|
||||
pub(crate) use self::irq::{IrqCallbackHandle, IrqLine};
|
||||
pub(crate) use self::irq::{allocate_target_irq, IrqCallbackHandle, IrqLine};
|
||||
use core::{fmt::Debug, mem::size_of_val};
|
||||
|
||||
use crate::{x86_64_util::*, *};
|
||||
|
@ -3,6 +3,7 @@ use alloc::vec::Vec;
|
||||
pub struct RecycleAllocator {
|
||||
current: usize,
|
||||
recycled: Vec<usize>,
|
||||
skip: Vec<usize>,
|
||||
max: usize,
|
||||
}
|
||||
|
||||
@ -11,6 +12,7 @@ impl RecycleAllocator {
|
||||
RecycleAllocator {
|
||||
current: 0,
|
||||
recycled: Vec::new(),
|
||||
skip: Vec::new(),
|
||||
max: usize::MAX - 1,
|
||||
}
|
||||
}
|
||||
@ -19,30 +21,73 @@ impl RecycleAllocator {
|
||||
RecycleAllocator {
|
||||
current: start,
|
||||
recycled: Vec::new(),
|
||||
skip: Vec::new(),
|
||||
max: max,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn alloc(&mut self) -> usize {
|
||||
if self.current == self.max && self.recycled.is_empty() {
|
||||
if let Some(id) = self.recycled.pop() {
|
||||
return id;
|
||||
}
|
||||
// recycle list is empty, need to use current to allocate an id.
|
||||
// it should skip the element in skip list
|
||||
while self.skip.contains(&self.current) {
|
||||
self.current += 1;
|
||||
}
|
||||
if self.current == self.max {
|
||||
return usize::MAX;
|
||||
}
|
||||
if let Some(id) = self.recycled.pop() {
|
||||
id
|
||||
} else {
|
||||
self.current += 1;
|
||||
self.current - 1
|
||||
}
|
||||
self.current += 1;
|
||||
self.current - 1
|
||||
}
|
||||
/// deallocate a id, it should fit one of the following requirement, otherwise it will panic:
|
||||
///
|
||||
/// 1. It is in the skip list
|
||||
///
|
||||
/// 2. It smaller than current and not in recycled list
|
||||
#[allow(unused)]
|
||||
pub fn dealloc(&mut self, id: usize) {
|
||||
assert!(id < self.current);
|
||||
assert!(
|
||||
!self.recycled.iter().any(|i| *i == id),
|
||||
"id {} has been deallocated!",
|
||||
id
|
||||
);
|
||||
if !self.skip.contains(&id) {
|
||||
assert!(id < self.current);
|
||||
assert!(
|
||||
!self.recycled.iter().any(|i| *i == id),
|
||||
"id {} has been deallocated!",
|
||||
id
|
||||
);
|
||||
} else {
|
||||
// if the value is in skip list, then remove it from the skip list
|
||||
self.skip.retain(|value| *value != id);
|
||||
}
|
||||
self.recycled.push(id);
|
||||
}
|
||||
|
||||
/// get target id in the list, it will return true if the target can used, false if can not used.
|
||||
/// the target need to meet one of the following requirement so that it can used:
|
||||
///
|
||||
/// 1. It is in the recycled list
|
||||
///
|
||||
/// 2. It is bigger than the current, smaller than max and not in the skip list
|
||||
///
|
||||
pub fn get_target(&mut self, target: usize) -> bool {
|
||||
if target >= self.max {
|
||||
return false;
|
||||
}
|
||||
if target >= self.current {
|
||||
if self.skip.contains(&target) {
|
||||
false
|
||||
} else {
|
||||
self.skip.push(target);
|
||||
true
|
||||
}
|
||||
} else {
|
||||
if self.recycled.contains(&target) {
|
||||
self.recycled.retain(|value| *value != target);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,13 @@ pub fn enable_interrupts_and_hlt() {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable_interrupts() {
|
||||
unsafe {
|
||||
asm!("sti", options(nomem, nostack));
|
||||
}
|
||||
}
|
||||
|
||||
pub const RING0: u16 = 0;
|
||||
pub const RING3: u16 = 3;
|
||||
|
||||
|
@ -124,7 +124,7 @@ impl BlockDevice for VirtioBlockDevice {
|
||||
|
||||
impl VirtioBlockDevice {
|
||||
fn new(mut virtio_device: PCIVirtioDevice) -> Self {
|
||||
fn handle_block_device(frame: TrapFrame) {
|
||||
fn handle_block_device(frame: &TrapFrame) {
|
||||
info!("pci block device queue interrupt");
|
||||
BLOCK_DEVICE.lock().as_ref().unwrap().handle_irq()
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ impl PCIVirtioDevice {
|
||||
/// register the queue interrupt functions, this function should call only once
|
||||
pub fn register_queue_interrupt_functions<F>(&mut self, functions: &mut Vec<F>)
|
||||
where
|
||||
F: Fn(TrapFrame) + Send + Sync + 'static,
|
||||
F: Fn(&TrapFrame) + Send + Sync + 'static,
|
||||
{
|
||||
let len = functions.len();
|
||||
if len
|
||||
|
46
src/tests/timer_test.rs
Normal file
46
src/tests/timer_test.rs
Normal file
@ -0,0 +1,46 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(custom_test_frameworks)]
|
||||
#![test_runner(kxos_frame::test_runner)]
|
||||
#![reexport_test_harness_main = "test_main"]
|
||||
use bootloader::{entry_point, BootInfo};
|
||||
use kxos_frame::timer::Timer;
|
||||
extern crate alloc;
|
||||
use alloc::sync::Arc;
|
||||
use core::time::Duration;
|
||||
use core::panic::PanicInfo;
|
||||
use kxos_frame::println;
|
||||
|
||||
static mut TICK: usize = 0;
|
||||
|
||||
entry_point!(kernel_test_main);
|
||||
|
||||
fn kernel_test_main(boot_info: &'static mut BootInfo) -> ! {
|
||||
kxos_frame::init(boot_info);
|
||||
test_main();
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
kxos_frame::test_panic_handler(info)
|
||||
}
|
||||
|
||||
#[test_case]
|
||||
fn test_timer() {
|
||||
println!("If you want to pass this test, you may need to enable the interrupt in kxos_frame/lib.rs");
|
||||
println!("make sure the Timer irq number 32 handler won't panic");
|
||||
unsafe {
|
||||
let timer = Timer::new(timer_callback).unwrap();
|
||||
timer.set(Duration::from_secs(1));
|
||||
while TICK < 5 {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timer_callback(timer: Arc<Timer>) {
|
||||
unsafe {
|
||||
TICK+=1;
|
||||
println!("TICK:{}",TICK);
|
||||
timer.set(Duration::from_secs(1));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user