Time (#11)
* WIP: Time syscalls * Count time from PIT using low tickrate * Implement realtime * Implement nanosleep with a tight loop
This commit is contained in:
parent
798f7c8808
commit
64cc730eac
|
@ -1,5 +1,7 @@
|
||||||
|
pub mod rtc;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
|
|
||||||
pub unsafe fn init(){
|
pub unsafe fn init(){
|
||||||
|
rtc::init();
|
||||||
serial::init();
|
serial::init();
|
||||||
}
|
}
|
||||||
|
|
109
arch/x86_64/src/device/rtc.rs
Normal file
109
arch/x86_64/src/device/rtc.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
use io::{Io, Pio};
|
||||||
|
use time;
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
let mut rtc = Rtc::new();
|
||||||
|
time::START.lock().0 = rtc.time();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cvt_bcd(value: usize) -> usize {
|
||||||
|
(value & 0xF) + ((value / 16) * 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RTC
|
||||||
|
pub struct Rtc {
|
||||||
|
addr: Pio<u8>,
|
||||||
|
data: Pio<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rtc {
|
||||||
|
/// Create new empty RTC
|
||||||
|
pub fn new() -> Self {
|
||||||
|
return Rtc {
|
||||||
|
addr: Pio::<u8>::new(0x70),
|
||||||
|
data: Pio::<u8>::new(0x71),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read
|
||||||
|
unsafe fn read(&mut self, reg: u8) -> u8 {
|
||||||
|
self.addr.write(reg);
|
||||||
|
return self.data.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wait
|
||||||
|
unsafe fn wait(&mut self) {
|
||||||
|
while self.read(0xA) & 0x80 != 0x80 {}
|
||||||
|
while self.read(0xA) & 0x80 == 0x80 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get time
|
||||||
|
pub fn time(&mut self) -> u64 {
|
||||||
|
let mut second;
|
||||||
|
let mut minute;
|
||||||
|
let mut hour;
|
||||||
|
let mut day;
|
||||||
|
let mut month;
|
||||||
|
let mut year;
|
||||||
|
let register_b;
|
||||||
|
unsafe {
|
||||||
|
self.wait();
|
||||||
|
second = self.read(0) as usize;
|
||||||
|
minute = self.read(2) as usize;
|
||||||
|
hour = self.read(4) as usize;
|
||||||
|
day = self.read(7) as usize;
|
||||||
|
month = self.read(8) as usize;
|
||||||
|
year = self.read(9) as usize;
|
||||||
|
register_b = self.read(0xB);
|
||||||
|
}
|
||||||
|
|
||||||
|
if register_b & 4 != 4 {
|
||||||
|
second = cvt_bcd(second);
|
||||||
|
minute = cvt_bcd(minute);
|
||||||
|
hour = cvt_bcd(hour & 0x7F) | (hour & 0x80);
|
||||||
|
day = cvt_bcd(day);
|
||||||
|
month = cvt_bcd(month);
|
||||||
|
year = cvt_bcd(year);
|
||||||
|
}
|
||||||
|
|
||||||
|
if register_b & 2 != 2 || hour & 0x80 == 0x80 {
|
||||||
|
hour = ((hour & 0x7F) + 12) % 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Century Register
|
||||||
|
year += 2000;
|
||||||
|
|
||||||
|
// Unix time from clock
|
||||||
|
let mut secs: u64 = (year as u64 - 1970) * 31536000;
|
||||||
|
|
||||||
|
let mut leap_days = (year as u64 - 1972) / 4 + 1;
|
||||||
|
if year % 4 == 0 {
|
||||||
|
if month <= 2 {
|
||||||
|
leap_days -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secs += leap_days * 86400;
|
||||||
|
|
||||||
|
match month {
|
||||||
|
2 => secs += 2678400,
|
||||||
|
3 => secs += 5097600,
|
||||||
|
4 => secs += 7776000,
|
||||||
|
5 => secs += 10368000,
|
||||||
|
6 => secs += 13046400,
|
||||||
|
7 => secs += 15638400,
|
||||||
|
8 => secs += 18316800,
|
||||||
|
9 => secs += 20995200,
|
||||||
|
10 => secs += 23587200,
|
||||||
|
11 => secs += 26265600,
|
||||||
|
12 => secs += 28857600,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
secs += (day as u64 - 1) * 86400;
|
||||||
|
secs += hour as u64 * 3600;
|
||||||
|
secs += minute as u64 * 60;
|
||||||
|
secs += second as u64;
|
||||||
|
|
||||||
|
secs
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ use spin::Mutex;
|
||||||
use x86::io;
|
use x86::io;
|
||||||
|
|
||||||
use device::serial::{COM1, COM2};
|
use device::serial::{COM1, COM2};
|
||||||
|
use time;
|
||||||
|
|
||||||
pub static ACKS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
|
pub static ACKS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
|
||||||
pub static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
|
pub static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
|
||||||
|
@ -27,6 +28,16 @@ pub unsafe fn acknowledge(irq: usize) {
|
||||||
|
|
||||||
interrupt!(pit, {
|
interrupt!(pit, {
|
||||||
COUNTS.lock()[0] += 1;
|
COUNTS.lock()[0] += 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
const PIT_RATE: u64 = 46500044;
|
||||||
|
|
||||||
|
let mut offset = time::OFFSET.lock();
|
||||||
|
let sum = offset.1 + PIT_RATE;
|
||||||
|
offset.1 = sum % 1000000000;
|
||||||
|
offset.0 += sum / 1000000000;
|
||||||
|
}
|
||||||
|
|
||||||
master_ack();
|
master_ack();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -218,3 +218,6 @@ pub mod panic;
|
||||||
|
|
||||||
/// Initialization and start function
|
/// Initialization and start function
|
||||||
pub mod start;
|
pub mod start;
|
||||||
|
|
||||||
|
/// Time
|
||||||
|
pub mod time;
|
||||||
|
|
15
arch/x86_64/src/time.rs
Normal file
15
arch/x86_64/src/time.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
pub static START: Mutex<(u64, u64)> = Mutex::new((0, 0));
|
||||||
|
pub static OFFSET: Mutex<(u64, u64)> = Mutex::new((0, 0));
|
||||||
|
|
||||||
|
pub fn monotonic() -> (u64, u64) {
|
||||||
|
*OFFSET.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn realtime() -> (u64, u64) {
|
||||||
|
let offset = monotonic();
|
||||||
|
let start = *START.lock();
|
||||||
|
let sum = start.1 + offset.1;
|
||||||
|
(start.0 + offset.0 + sum / 1000000000, sum % 1000000000)
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ initialize:
|
||||||
|
|
||||||
.pit:
|
.pit:
|
||||||
;initialize the PIT
|
;initialize the PIT
|
||||||
mov ax, 65535 ;5370 ;this is the divider for the PIT
|
mov ax, 55483 ;5370 ;this is the divider for the PIT
|
||||||
out 0x40, al
|
out 0x40, al
|
||||||
rol ax, 8
|
rol ax, 8
|
||||||
out 0x40, al
|
out 0x40, al
|
||||||
|
|
|
@ -3,7 +3,6 @@ use collections::{BTreeMap, VecDeque};
|
||||||
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||||
use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
|
|
||||||
use context;
|
|
||||||
use syscall::error::{Error, Result, EBADF, EPIPE};
|
use syscall::error::{Error, Result, EBADF, EPIPE};
|
||||||
use syscall::scheme::Scheme;
|
use syscall::scheme::Scheme;
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,10 @@ pub use self::syscall::{data, error, flag, number, scheme};
|
||||||
|
|
||||||
pub use self::fs::*;
|
pub use self::fs::*;
|
||||||
pub use self::process::*;
|
pub use self::process::*;
|
||||||
|
pub use self::time::*;
|
||||||
pub use self::validate::*;
|
pub use self::validate::*;
|
||||||
|
|
||||||
|
use self::data::TimeSpec;
|
||||||
use self::error::{Error, Result, ENOSYS};
|
use self::error::{Error, Result, ENOSYS};
|
||||||
use self::number::*;
|
use self::number::*;
|
||||||
|
|
||||||
|
@ -17,6 +19,9 @@ pub mod fs;
|
||||||
/// Process syscalls
|
/// Process syscalls
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
|
||||||
|
/// Time syscalls
|
||||||
|
pub mod time;
|
||||||
|
|
||||||
/// Validate input
|
/// Validate input
|
||||||
pub mod validate;
|
pub mod validate;
|
||||||
|
|
||||||
|
@ -52,6 +57,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
|
||||||
SYS_IOPL => iopl(b),
|
SYS_IOPL => iopl(b),
|
||||||
SYS_CLONE => clone(b, stack),
|
SYS_CLONE => clone(b, stack),
|
||||||
SYS_YIELD => sched_yield(),
|
SYS_YIELD => sched_yield(),
|
||||||
|
SYS_NANOSLEEP => nanosleep(validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?, validate_slice_mut(c as *mut TimeSpec, 1).ok().map(|rem| &mut rem[0])),
|
||||||
SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
|
SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
|
||||||
SYS_GETUID => getuid(),
|
SYS_GETUID => getuid(),
|
||||||
SYS_GETGID => getgid(),
|
SYS_GETGID => getgid(),
|
||||||
|
@ -59,6 +65,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
|
||||||
SYS_GETEGID => getegid(),
|
SYS_GETEGID => getegid(),
|
||||||
SYS_SETUID => setuid(b as u32),
|
SYS_SETUID => setuid(b as u32),
|
||||||
SYS_SETGID => setgid(b as u32),
|
SYS_SETGID => setgid(b as u32),
|
||||||
|
SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
|
||||||
SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
|
SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
|
||||||
SYS_PHYSALLOC => physalloc(b),
|
SYS_PHYSALLOC => physalloc(b),
|
||||||
SYS_PHYSFREE => physfree(b, c),
|
SYS_PHYSFREE => physfree(b, c),
|
||||||
|
|
|
@ -770,11 +770,6 @@ pub fn physunmap(virtual_address: usize) -> Result<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sched_yield() -> Result<usize> {
|
|
||||||
unsafe { context::switch(); }
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setgid(gid: u32) -> Result<usize> {
|
pub fn setgid(gid: u32) -> Result<usize> {
|
||||||
let contexts = context::contexts();
|
let contexts = context::contexts();
|
||||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
||||||
|
|
50
kernel/syscall/time.rs
Normal file
50
kernel/syscall/time.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use arch;
|
||||||
|
use context;
|
||||||
|
use syscall::data::TimeSpec;
|
||||||
|
use syscall::error::*;
|
||||||
|
use syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC};
|
||||||
|
|
||||||
|
pub fn clock_gettime(clock: usize, time: &mut TimeSpec) -> Result<usize> {
|
||||||
|
match clock {
|
||||||
|
CLOCK_REALTIME => {
|
||||||
|
let arch_time = arch::time::realtime();
|
||||||
|
time.tv_sec = arch_time.0 as i64;
|
||||||
|
time.tv_nsec = arch_time.1 as i32;
|
||||||
|
Ok(0)
|
||||||
|
},
|
||||||
|
CLOCK_MONOTONIC => {
|
||||||
|
let arch_time = arch::time::monotonic();
|
||||||
|
time.tv_sec = arch_time.0 as i64;
|
||||||
|
time.tv_nsec = arch_time.1 as i32;
|
||||||
|
Ok(0)
|
||||||
|
},
|
||||||
|
_ => Err(Error::new(EINVAL))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nanosleep(req: &TimeSpec, rem_opt: Option<&mut TimeSpec>) -> Result<usize> {
|
||||||
|
let start = arch::time::monotonic();
|
||||||
|
let sum = start.1 + req.tv_nsec as u64;
|
||||||
|
let end = (start.0 + req.tv_sec as u64 + sum / 1000000000, sum % 1000000000);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
unsafe { context::switch(); }
|
||||||
|
|
||||||
|
let current = arch::time::monotonic();
|
||||||
|
if current.0 > end.0 || (current.0 == end.0 && current.1 >= end.1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut rem) = rem_opt {
|
||||||
|
rem.tv_sec = 0;
|
||||||
|
rem.tv_nsec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sched_yield() -> Result<usize> {
|
||||||
|
unsafe { context::switch(); }
|
||||||
|
Ok(0)
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ pub const CLONE_VFORK: usize = 0x4000;
|
||||||
/// This is an important security measure, since otherwise the process would be able to fork it
|
/// This is an important security measure, since otherwise the process would be able to fork it
|
||||||
/// self right after starting, making supervising it impossible.
|
/// self right after starting, making supervising it impossible.
|
||||||
pub const CLONE_SUPERVISE: usize = 0x400000;
|
pub const CLONE_SUPERVISE: usize = 0x400000;
|
||||||
|
|
||||||
pub const CLOCK_REALTIME: usize = 1;
|
pub const CLOCK_REALTIME: usize = 1;
|
||||||
pub const CLOCK_MONOTONIC: usize = 4;
|
pub const CLOCK_MONOTONIC: usize = 4;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue