mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Merge pull request #56 from sdww0/main
Real Time Clock support, read special character from QEMU console
This commit is contained in:
commit
4629b8a15e
7
src/Cargo.lock
generated
7
src/Cargo.lock
generated
@ -25,6 +25,12 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ascii"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -158,6 +164,7 @@ dependencies = [
|
|||||||
name = "jinux-std"
|
name = "jinux-std"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ascii",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"jinux-frame",
|
"jinux-frame",
|
||||||
"jinux-pci",
|
"jinux-pci",
|
||||||
|
@ -7,6 +7,7 @@ pub mod apic;
|
|||||||
pub mod ioapic;
|
pub mod ioapic;
|
||||||
pub mod pic;
|
pub mod pic;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
pub mod rtc;
|
||||||
|
|
||||||
pub use apic::ack;
|
pub use apic::ack;
|
||||||
pub use timer::TimerCallback;
|
pub use timer::TimerCallback;
|
||||||
@ -27,4 +28,5 @@ pub(crate) fn init(rsdp: Option<u64>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pic::init();
|
pic::init();
|
||||||
|
rtc::init();
|
||||||
}
|
}
|
||||||
|
72
src/framework/jinux-frame/src/driver/rtc.rs
Normal file
72
src/framework/jinux-frame/src/driver/rtc.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use core::sync::atomic::AtomicU8;
|
||||||
|
use core::sync::atomic::Ordering::Relaxed;
|
||||||
|
|
||||||
|
use acpi::{sdt::Signature, fadt::Fadt};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use crate::{x86_64_util::{out8, in8}, time::Time};
|
||||||
|
|
||||||
|
use super::acpi::ACPI_TABLES;
|
||||||
|
|
||||||
|
const CMOS_ADDRESS : u16 = 0x70;
|
||||||
|
const CMOS_DATA : u16 = 0x71;
|
||||||
|
pub(crate) static CENTURY_REGISTER : AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
lazy_static!{
|
||||||
|
static ref READ_TIME : Mutex<Time> = Mutex::new(Time::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(){
|
||||||
|
let c = ACPI_TABLES.lock();
|
||||||
|
let r_century = unsafe{
|
||||||
|
let a = c.get_sdt::<Fadt>(Signature::FADT).unwrap().expect("not found FACP in ACPI table");
|
||||||
|
a.century
|
||||||
|
};
|
||||||
|
CENTURY_REGISTER.store(r_century, Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cmos(reg: u8) -> u8{
|
||||||
|
out8(CMOS_ADDRESS, reg as u8);
|
||||||
|
in8(CMOS_DATA)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_updating() -> bool{
|
||||||
|
out8(CMOS_ADDRESS,0x0A);
|
||||||
|
in8(CMOS_DATA) & 0x80 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read()-> Time{
|
||||||
|
update_time();
|
||||||
|
READ_TIME.lock().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read year,month,day and other data
|
||||||
|
/// ref: https://wiki.osdev.org/CMOS#Reading_All_RTC_Time_and_Date_Registers
|
||||||
|
fn update_time(){
|
||||||
|
let mut last_time :Time;
|
||||||
|
|
||||||
|
let register_b : u8;
|
||||||
|
let mut lock = READ_TIME.lock();
|
||||||
|
|
||||||
|
lock.update_from_rtc();
|
||||||
|
|
||||||
|
last_time = lock.clone();
|
||||||
|
|
||||||
|
lock.update_from_rtc();
|
||||||
|
|
||||||
|
|
||||||
|
while *lock!=last_time{
|
||||||
|
last_time = lock.clone();
|
||||||
|
|
||||||
|
lock.update_from_rtc();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
register_b = get_cmos(0x0B);
|
||||||
|
|
||||||
|
lock.convert_bcd_to_binary(register_b);
|
||||||
|
lock.convert_12_hour_to_24_hour(register_b);
|
||||||
|
lock.modify_year();
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ pub mod user;
|
|||||||
mod util;
|
mod util;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
pub(crate) mod x86_64_util;
|
pub(crate) mod x86_64_util;
|
||||||
|
pub mod time;
|
||||||
|
|
||||||
use core::{mem, panic::PanicInfo};
|
use core::{mem, panic::PanicInfo};
|
||||||
pub use driver::ack as apic_ack;
|
pub use driver::ack as apic_ack;
|
||||||
|
75
src/framework/jinux-frame/src/time.rs
Normal file
75
src/framework/jinux-frame/src/time.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use crate::driver::rtc::{get_cmos, is_updating, CENTURY_REGISTER, read};
|
||||||
|
use core::sync::atomic::Ordering::Relaxed;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug,Clone, Copy,Default,PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Time{
|
||||||
|
century: u8,
|
||||||
|
pub year: u16,
|
||||||
|
pub month: u8,
|
||||||
|
pub day: u8,
|
||||||
|
pub hour: u8,
|
||||||
|
pub minute: u8,
|
||||||
|
pub second: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Time{
|
||||||
|
pub(crate) fn update_from_rtc(&mut self){
|
||||||
|
while is_updating(){}
|
||||||
|
self.second = get_cmos(0x00);
|
||||||
|
self.minute = get_cmos(0x02);
|
||||||
|
self.hour = get_cmos(0x04);
|
||||||
|
self.day = get_cmos(0x07);
|
||||||
|
self.month = get_cmos(0x08);
|
||||||
|
self.year = get_cmos(0x09) as u16;
|
||||||
|
|
||||||
|
let century_register = CENTURY_REGISTER.load(Relaxed);
|
||||||
|
|
||||||
|
if century_register !=0{
|
||||||
|
self.century = get_cmos(century_register);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// convert BCD to binary values
|
||||||
|
/// ref:https://wiki.osdev.org/CMOS#Reading_All_RTC_Time_and_Date_Registers
|
||||||
|
pub(crate) fn convert_bcd_to_binary(&mut self,register_b: u8){
|
||||||
|
if register_b & 0x04 == 0{
|
||||||
|
let century_register = CENTURY_REGISTER.load(Relaxed);
|
||||||
|
self.second = (self.second & 0x0F) + ((self.second / 16) * 10);
|
||||||
|
self.minute = (self.minute & 0x0F) + ((self.minute / 16) * 10);
|
||||||
|
self.hour = ( (self.hour & 0x0F) + (((self.hour & 0x70) / 16) * 10) ) | (self.hour & 0x80);
|
||||||
|
self.day = (self.day & 0x0F) + ((self.day / 16) * 10);
|
||||||
|
self.month = (self.month & 0x0F) + ((self.month / 16) * 10);
|
||||||
|
self.year = (self.year & 0x0F) + ((self.year / 16) * 10);
|
||||||
|
if century_register != 0 {
|
||||||
|
self.century = (self.century & 0x0F) + ((self.century / 16) * 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// convert 12 hour clock to 24 hour clock
|
||||||
|
pub(crate) fn convert_12_hour_to_24_hour(&mut self,register_b:u8){
|
||||||
|
// bit1 in register_b is not set if 12 hour format is enable
|
||||||
|
// if highest bit in hour is set, then it is pm
|
||||||
|
if ((register_b & 0x02)==0) && ((self.hour & 0x80) !=0){
|
||||||
|
self.hour = ((self.hour & 0x7F) + 12) % 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// convert raw year (10, 20 etc.) to real year (2010, 2020 etc.)
|
||||||
|
pub(crate) fn modify_year(&mut self){
|
||||||
|
let century_register = CENTURY_REGISTER.load(Relaxed);
|
||||||
|
if century_register !=0{
|
||||||
|
self.year += self.century as u16 * 100;
|
||||||
|
}else{
|
||||||
|
panic!("century register not exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get real time
|
||||||
|
pub fn get_real_time() -> Time{
|
||||||
|
read()
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ const COMMON_ARGS: &[&str] = &[
|
|||||||
"-device",
|
"-device",
|
||||||
"virtio-keyboard-pci",
|
"virtio-keyboard-pci",
|
||||||
"-serial",
|
"-serial",
|
||||||
"stdio",
|
"mon:stdio",
|
||||||
"-display",
|
"-display",
|
||||||
"none",
|
"none",
|
||||||
];
|
];
|
||||||
|
@ -16,6 +16,7 @@ typeflags-util = {path="../typeflags-util"}
|
|||||||
jinux-rights-proc = {path="../jinux-rights-proc"}
|
jinux-rights-proc = {path="../jinux-rights-proc"}
|
||||||
jinux-util = {path="../jinux-util"}
|
jinux-util = {path="../jinux-util"}
|
||||||
virtio-input-decoder = "0.1.4"
|
virtio-input-decoder = "0.1.4"
|
||||||
|
ascii = { version = "1.1", default-features = false, features = ["alloc"] }
|
||||||
|
|
||||||
# parse elf file
|
# parse elf file
|
||||||
xmas-elf = "0.8.0"
|
xmas-elf = "0.8.0"
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
|
use jinux_frame::println;
|
||||||
|
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
use jinux_frame::TrapFrame;
|
use jinux_frame::{TrapFrame, receive_char, info};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use crate::{process::Process, current};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref KEYBOARD_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
static ref KEYBOARD_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
||||||
Mutex::new(Vec::new());
|
Mutex::new(Vec::new());
|
||||||
|
static ref WAIT_INPUT_PROCESS : Mutex<Option<Arc<Process>>> = Mutex::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
jinux_frame::device::console::register_console_input_callback(handle_irq)
|
jinux_frame::device::console::register_console_input_callback(handle_irq);
|
||||||
|
register_console_callback(Arc::new(console_receive_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_irq(trap_frame: &TrapFrame) {
|
fn handle_irq(trap_frame: &TrapFrame) {
|
||||||
@ -25,3 +31,24 @@ fn handle_irq(trap_frame: &TrapFrame) {
|
|||||||
pub fn register_console_callback(callback: Arc<dyn Fn(u8) + 'static + Send + Sync>) {
|
pub fn register_console_callback(callback: Arc<dyn Fn(u8) + 'static + Send + Sync>) {
|
||||||
KEYBOARD_CALLBACKS.lock().push(callback);
|
KEYBOARD_CALLBACKS.lock().push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn console_receive_callback(data: u8){
|
||||||
|
let process = WAIT_INPUT_PROCESS.lock().take();
|
||||||
|
process.unwrap().send_to_scheduler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// receive char from console, if there is no data in buffer, then it will switch to other task
|
||||||
|
/// until it is notified.
|
||||||
|
pub fn receive_console_char() -> u8{
|
||||||
|
loop{
|
||||||
|
if let Some(byte) = receive_char() {
|
||||||
|
return byte;
|
||||||
|
}else if WAIT_INPUT_PROCESS.lock().is_none(){
|
||||||
|
WAIT_INPUT_PROCESS.lock().replace(current!());
|
||||||
|
Process::yield_now();
|
||||||
|
WAIT_INPUT_PROCESS.lock().take();
|
||||||
|
}else{
|
||||||
|
panic!("there is process waiting in the console receive list!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -271,7 +271,7 @@ pub fn syscall_dispatch(
|
|||||||
SYS_TGKILL => syscall_handler!(3, sys_tgkill, args),
|
SYS_TGKILL => syscall_handler!(3, sys_tgkill, args),
|
||||||
SYS_WAITID => syscall_handler!(5, sys_waitid, args),
|
SYS_WAITID => syscall_handler!(5, sys_waitid, args),
|
||||||
SYS_OPENAT => syscall_handler!(4, sys_openat, args),
|
SYS_OPENAT => syscall_handler!(4, sys_openat, args),
|
||||||
_ => panic!("Unsupported syscall number: {}", syscall_number),
|
_ => panic!("Unsupported syscall number: {}, args:{:x?}", syscall_number,args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use jinux_frame::receive_char;
|
|
||||||
|
|
||||||
use self::line_discipline::LineDiscipline;
|
use self::line_discipline::LineDiscipline;
|
||||||
|
use crate::driver::console::receive_console_char;
|
||||||
use crate::fs::events::IoEvents;
|
use crate::fs::events::IoEvents;
|
||||||
use crate::fs::ioctl::IoctlCmd;
|
use crate::fs::ioctl::IoctlCmd;
|
||||||
use crate::process::Pgid;
|
use crate::process::Pgid;
|
||||||
@ -55,13 +55,10 @@ impl File for Tty {
|
|||||||
if !self.ldisc.lock().is_empty() {
|
if !self.ldisc.lock().is_empty() {
|
||||||
return IoEvents::POLLIN;
|
return IoEvents::POLLIN;
|
||||||
}
|
}
|
||||||
loop {
|
// receive keyboard input
|
||||||
// receive keyboard input
|
let byte = receive_console_char();
|
||||||
if let Some(byte) = receive_char() {
|
self.ldisc.lock().push_char(byte);
|
||||||
self.ldisc.lock().push_char(byte);
|
return IoEvents::POLLIN;
|
||||||
return IoEvents::POLLIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||||
|
30
src/tests/rtc.rs
Normal file
30
src/tests/rtc.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(custom_test_frameworks)]
|
||||||
|
#![test_runner(jinux_frame::test_runner)]
|
||||||
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
use bootloader::{entry_point, BootInfo};
|
||||||
|
extern crate alloc;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
use jinux_frame::println;
|
||||||
|
|
||||||
|
static mut INPUT_VALUE: u8 = 0;
|
||||||
|
|
||||||
|
entry_point!(kernel_test_main);
|
||||||
|
|
||||||
|
fn kernel_test_main(boot_info: &'static mut BootInfo) -> ! {
|
||||||
|
jinux_frame::init(boot_info);
|
||||||
|
test_main();
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
jinux_frame::test_panic_handler(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_rtc() {
|
||||||
|
println!("real time:{:?}",jinux_frame::time::get_real_time());
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user