Merge pull request #56 from sdww0/main

Real Time Clock support, read special character from QEMU console
This commit is contained in:
Tate, Hongliang Tian 2023-01-06 11:22:30 +08:00 committed by GitHub
commit 4629b8a15e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 224 additions and 12 deletions

7
src/Cargo.lock generated
View File

@ -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",

View File

@ -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();
}

View 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();
}

View File

@ -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;

View 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()
}

View File

@ -16,7 +16,7 @@ const COMMON_ARGS: &[&str] = &[
"-device",
"virtio-keyboard-pci",
"-serial",
"stdio",
"mon:stdio",
"-display",
"none",
];

View File

@ -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"

View File

@ -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!");
}
}
}

View File

@ -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),
}
}

View File

@ -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> {

30
src/tests/rtc.rs Normal file
View 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());
}