Merge pull request #56 from sdww0/main
Real Time Clock support, read special character from QEMU console
This commit is contained in:
commit
4629b8a15e
|
@ -25,6 +25,12 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
@ -158,6 +164,7 @@ dependencies = [
|
|||
name = "jinux-std"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"bitflags",
|
||||
"jinux-frame",
|
||||
"jinux-pci",
|
||||
|
|
|
@ -7,6 +7,7 @@ pub mod apic;
|
|||
pub mod ioapic;
|
||||
pub mod pic;
|
||||
pub mod timer;
|
||||
pub mod rtc;
|
||||
|
||||
pub use apic::ack;
|
||||
pub use timer::TimerCallback;
|
||||
|
@ -27,4 +28,5 @@ pub(crate) fn init(rsdp: Option<u64>) {
|
|||
}
|
||||
}
|
||||
pic::init();
|
||||
rtc::init();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
pub mod vm;
|
||||
pub(crate) mod x86_64_util;
|
||||
pub mod time;
|
||||
|
||||
use core::{mem, panic::PanicInfo};
|
||||
pub use driver::ack as apic_ack;
|
||||
|
|
|
@ -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",
|
||||
"virtio-keyboard-pci",
|
||||
"-serial",
|
||||
"stdio",
|
||||
"mon:stdio",
|
||||
"-display",
|
||||
"none",
|
||||
];
|
||||
|
|
|
@ -16,6 +16,7 @@ typeflags-util = {path="../typeflags-util"}
|
|||
jinux-rights-proc = {path="../jinux-rights-proc"}
|
||||
jinux-util = {path="../jinux-util"}
|
||||
virtio-input-decoder = "0.1.4"
|
||||
ascii = { version = "1.1", default-features = false, features = ["alloc"] }
|
||||
|
||||
# parse elf file
|
||||
xmas-elf = "0.8.0"
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
use jinux_frame::println;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use jinux_frame::TrapFrame;
|
||||
use jinux_frame::{TrapFrame, receive_char, info};
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::{process::Process, current};
|
||||
|
||||
lazy_static! {
|
||||
static ref KEYBOARD_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
||||
Mutex::new(Vec::new());
|
||||
static ref WAIT_INPUT_PROCESS : Mutex<Option<Arc<Process>>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -25,3 +31,24 @@ fn handle_irq(trap_frame: &TrapFrame) {
|
|||
pub fn register_console_callback(callback: Arc<dyn Fn(u8) + 'static + Send + Sync>) {
|
||||
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_WAITID => syscall_handler!(5, sys_waitid, 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 crate::driver::console::receive_console_char;
|
||||
use crate::fs::events::IoEvents;
|
||||
use crate::fs::ioctl::IoctlCmd;
|
||||
use crate::process::Pgid;
|
||||
|
@ -55,13 +55,10 @@ impl File for Tty {
|
|||
if !self.ldisc.lock().is_empty() {
|
||||
return IoEvents::POLLIN;
|
||||
}
|
||||
loop {
|
||||
// receive keyboard input
|
||||
if let Some(byte) = receive_char() {
|
||||
self.ldisc.lock().push_char(byte);
|
||||
return IoEvents::POLLIN;
|
||||
}
|
||||
}
|
||||
// receive keyboard input
|
||||
let byte = receive_console_char();
|
||||
self.ldisc.lock().push_char(byte);
|
||||
return IoEvents::POLLIN;
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
|
|
|
@ -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…
Reference in New Issue