feature: x86_64 timer and sleep

This commit is contained in:
2022-03-22 18:12:15 +02:00
parent f372ed65c7
commit 07b62026fa
10 changed files with 255 additions and 111 deletions
+3 -1
View File
@@ -94,7 +94,9 @@ extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
virt_base: virt,
});
unsafe {
x86_64::COM1.init_irqs();
x86_64::COM1.init_irqs().unwrap();
x86_64::local_timer().init_irqs().unwrap();
x86_64::local_timer().enable().unwrap();
}
font::init();
debug::set_display(&x86_64::DISPLAY);
+34 -28
View File
@@ -1,10 +1,10 @@
use crate::arch::platform::ForkFrame;
use crate::mem::{
self,
phys::{self, PageUsage},
};
use crate::arch::platform::ForkFrame;
use core::mem::size_of;
use core::arch::global_asm;
use core::mem::size_of;
struct Stack {
bp: usize,
@@ -66,7 +66,7 @@ impl Context {
Self {
k_sp: stack.sp,
stack_base: stack.bp,
stack_page_count: 8
stack_page_count: 8,
}
}
@@ -75,7 +75,13 @@ impl Context {
/// # Safety
///
/// Unsafe: may clobber an already active context
pub unsafe fn setup_signal_entry(&mut self, entry: usize, arg: usize, cr3: usize, ustack: usize) {
pub unsafe fn setup_signal_entry(
&mut self,
entry: usize,
arg: usize,
cr3: usize,
ustack: usize,
) {
let cr3 = cr3 & 0xFFFFFFFF;
let mut stack = Stack::from_base_size(self.stack_base, self.stack_page_count);
let stack_top = stack.sp;
@@ -98,24 +104,24 @@ impl Context {
stack.push(frame.saved_rip);
stack.push(frame.saved_rsp);
stack.push(frame.x[6]); // rax
stack.push(frame.x[5]); // r9
stack.push(frame.x[4]); // r8
stack.push(frame.x[3]); // r10
stack.push(frame.x[2]); // rdx
stack.push(frame.x[1]); // rsi
stack.push(frame.x[0]); // rdi
stack.push(frame.x[6]); // rax
stack.push(frame.x[5]); // r9
stack.push(frame.x[4]); // r8
stack.push(frame.x[3]); // r10
stack.push(frame.x[2]); // rdx
stack.push(frame.x[1]); // rsi
stack.push(frame.x[0]); // rdi
// Setup common
stack.push(__x86_64_ctx_enter_from_fork as usize); // return address
stack.push(stack_top); // gs_base
stack.push(__x86_64_ctx_enter_from_fork as usize); // return address
stack.push(stack_top); // gs_base
stack.push(cr3);
stack.push(frame.x[9]); // r15
stack.push(frame.x[10]); // r14
stack.push(frame.x[11]); // r13
stack.push(frame.x[12]); // r12
stack.push(frame.x[7]); // rbx
stack.push(frame.x[8]); // rbp
stack.push(frame.x[9]); // r15
stack.push(frame.x[10]); // r14
stack.push(frame.x[11]); // r13
stack.push(frame.x[12]); // r12
stack.push(frame.x[7]); // rbx
stack.push(frame.x[8]); // rbp
Self {
k_sp: stack.sp,
@@ -159,20 +165,20 @@ impl Stack {
pub unsafe fn from_base_size(bp: usize, page_count: usize) -> Stack {
Stack {
bp,
sp: bp + page_count * mem::PAGE_SIZE
sp: bp + page_count * mem::PAGE_SIZE,
}
}
pub fn setup_common(&mut self, entry: usize, cr3: usize, tss_rsp0: usize) {
self.push(entry); // return address
self.push(tss_rsp0); // gs_base
self.push(entry); // return address
self.push(tss_rsp0); // gs_base
self.push(cr3);
self.push(0); // r15
self.push(0); // r14
self.push(0); // r13
self.push(0); // r12
self.push(0); // rbx
self.push(0); // rbp
self.push(0); // r15
self.push(0); // r14
self.push(0); // r13
self.push(0); // r12
self.push(0); // rbx
self.push(0); // rbp
}
pub fn push(&mut self, value: usize) {
+2 -7
View File
@@ -70,11 +70,7 @@ impl IntController for I8259 {
irq: Self::IrqNumber,
handler: &'static (dyn IntSource + Sync),
) -> Result<(), Errno> {
if irq.0 == 0 {
return Err(Errno::InvalidArgument);
}
let index = (irq.0 - 1) as usize;
let index = irq.0 as usize;
let mut lock = self.table.lock();
if lock[index].is_some() {
return Err(Errno::AlreadyExists);
@@ -98,7 +94,6 @@ impl IntController for I8259 {
fn handle_pending_irqs<'irq_context>(&'irq_context self, ic: &IrqContext<'irq_context>) {
let irq_number = ic.token();
assert!(irq_number > 0);
// Clear irq
if irq_number > 8 {
@@ -108,7 +103,7 @@ impl IntController for I8259 {
{
let table = self.table.lock();
match table[irq_number - 1] {
match table[irq_number] {
None => panic!("No handler registered for irq{}", irq_number),
Some(handler) => {
drop(table);
+45 -44
View File
@@ -47,51 +47,52 @@ __x86_64_irq_\no:
.section .text
__x86_64_irq_0:
cli
push %rax
push %rcx
push %rdx
push %rbx
push %rbp
push %rsi
push %rdi
push %r8
push %r9
push %r10
push %r11
push %r12
push %r13
push %r14
push %r15
mov $0x20, %al
mov $0x20, %dx
outb %al, %dx
call sched_yield
pop %r15
pop %r14
pop %r13
pop %r12
pop %r11
pop %r10
pop %r9
pop %r8
pop %rdi
pop %rsi
pop %rbp
pop %rbx
pop %rdx
pop %rcx
pop %rax
iretq
// __x86_64_irq_0:
// cli
//
// push %rax
// push %rcx
// push %rdx
// push %rbx
// push %rbp
// push %rsi
// push %rdi
//
// push %r8
// push %r9
// push %r10
// push %r11
// push %r12
// push %r13
// push %r14
// push %r15
//
// mov $0x20, %al
// mov $0x20, %dx
// outb %al, %dx
//
// call sched_yield
//
// pop %r15
// pop %r14
// pop %r13
// pop %r12
// pop %r11
// pop %r10
// pop %r9
// pop %r8
//
// pop %rdi
// pop %rsi
// pop %rbp
// pop %rbx
// pop %rdx
// pop %rcx
// pop %rax
//
// iretq
irq_entry 0
irq_entry 1
irq_entry 2
irq_entry 3
+7
View File
@@ -6,6 +6,8 @@ use uart::Uart;
mod intc;
use intc::I8259;
pub use intc::IrqNumber;
mod timer;
use timer::Timer;
mod io;
pub(self) use io::PortIo;
@@ -55,6 +57,11 @@ pub fn console() -> &'static impl SerialDevice {
&COM1
}
pub fn local_timer() -> &'static Timer {
&TIMER
}
static COM1: Uart = unsafe { Uart::new(0x3F8, IrqNumber::new(4)) };
pub(self) static INTC: I8259 = I8259::new();
pub(self) static DISPLAY: StaticFramebuffer = StaticFramebuffer::uninit();
pub(self) static TIMER: Timer = Timer::new(IrqNumber::new(0));
+71
View File
@@ -0,0 +1,71 @@
//! i.... timer implementation
use crate::arch::machine::{self, IrqNumber, PortIo};
use crate::dev::{
irq::{IntController, IntSource},
pseudo,
timer::TimestampSource,
Device,
};
use crate::proc;
use core::time::Duration;
use libsys::error::Errno;
use tock_registers::interfaces::{Readable, Writeable};
use core::sync::atomic::{AtomicU64, Ordering};
// 1.1931816666 MHz base freq
/// Generic timer struct
pub struct Timer {
data0: PortIo<u8>,
cmd: PortIo<u8>,
counter: AtomicU64,
irq: IrqNumber
}
impl Device for Timer {
fn name(&self) -> &'static str {
"Intel Timer"
}
unsafe fn enable(&self) -> Result<(), Errno> {
const DIV: u16 = (1193182u32 / 1000) as u16;
self.data0.write((DIV & 0xFF) as u8);
self.data0.write((DIV >> 8) as u8);
Ok(())
}
}
impl TimestampSource for Timer {
fn timestamp(&self) -> Result<Duration, Errno> {
Ok(Duration::from_millis(self.counter.load(Ordering::Relaxed)))
}
}
impl IntSource for Timer {
fn handle_irq(&self) -> Result<(), Errno> {
self.counter.fetch_add(1, Ordering::Relaxed);
proc::wait::tick();
proc::switch();
Ok(())
}
fn init_irqs(&'static self) -> Result<(), Errno> {
machine::INTC.register_handler(self.irq, self)?;
machine::INTC.enable_irq(self.irq)?;
Ok(())
}
}
impl Timer {
/// Constructs a new instance of ARM Generic Timer
pub const fn new(irq: IrqNumber) -> Self {
Self {
data0: unsafe { PortIo::new(0x40) },
cmd: unsafe { PortIo::new(0x43) },
counter: AtomicU64::new(0),
irq
}
}
}
+45 -22
View File
@@ -39,12 +39,35 @@ pub static WAIT_SELECT: Wait = Wait::new("select");
/// Checks for any timed out wait channels and interrupts them
pub fn tick() {
todo!();
let time = machine::local_timer().timestamp().unwrap();
let mut list = TICK_LIST.lock();
let mut cursor = list.cursor_front_mut();
while let Some(item) = cursor.current() {
if time > item.deadline {
let tid = item.tid;
cursor.remove_current();
SCHED.enqueue(tid);
} else {
cursor.move_next();
}
}
}
/// Suspends current process for given duration
pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> {
todo!()
// Dummy wait descriptor which will never receive notifications
static SLEEP_NOTIFY: Wait = Wait::new("sleep");
let deadline = machine::local_timer().timestamp()? + timeout;
match SLEEP_NOTIFY.wait(Some(deadline)) {
Err(Errno::Interrupt) => {
*remaining = deadline - machine::local_timer().timestamp()?;
Err(Errno::Interrupt)
}
Err(Errno::TimedOut) => Ok(()),
Ok(_) => panic!("Impossible result"),
res => res,
}
}
/// Suspends current process until some file descriptor
@@ -146,12 +169,12 @@ impl Wait {
queue_lock.push_back(thread.id());
thread.setup_wait(self);
// if let Some(deadline) = deadline {
// TICK_LIST.lock().push_back(Timeout {
// tid: thread.id(),
// deadline,
// });
// }
if let Some(deadline) = deadline {
TICK_LIST.lock().push_back(Timeout {
tid: thread.id(),
deadline,
});
}
loop {
match thread.wait_status() {
@@ -168,22 +191,22 @@ impl Wait {
thread.enter_wait();
queue_lock = self.queue.lock();
// if let Some(deadline) = deadline {
// if machine::local_timer().timestamp()? > deadline {
// let mut cursor = queue_lock.cursor_front_mut();
if let Some(deadline) = deadline {
if machine::local_timer().timestamp()? > deadline {
let mut cursor = queue_lock.cursor_front_mut();
// while let Some(&mut item) = cursor.current() {
// if thread.id() == item {
// cursor.remove_current();
// break;
// } else {
// cursor.move_next();
// }
// }
while let Some(&mut item) = cursor.current() {
if thread.id() == item {
cursor.remove_current();
break;
} else {
cursor.move_next();
}
}
// return Err(Errno::TimedOut);
// }
// }
return Err(Errno::TimedOut);
}
}
}
}
}
+9
View File
@@ -122,6 +122,15 @@ pub fn option_struct_mut<'a, T>(base: usize) -> Result<Option<&'a mut T>, Errno>
}
}
/// Checks given argument and interprets it as a `Option<&'a mut [T]>`
pub fn option_struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<Option<&'a mut [T]>, Errno> {
if base == 0 {
Ok(None)
} else {
struct_buf_mut(base, count).map(Some)
}
}
/// Validates that the argument pointer is accessible for requested operation
/// for current process
pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
+4 -3
View File
@@ -314,13 +314,14 @@ fn _syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
SystemCall::GetPid => Ok(u32::from(Process::current().id()) as usize),
SystemCall::GetTid => Ok(u32::from(Thread::current().id()) as usize),
SystemCall::Sleep => {
let rem_buf = arg::option_buf_ref(args[1], size_of::<u64>() * 2)?;
let rem_buf = arg::option_struct_buf_mut::<u64>(args[1], size_of::<u64>() * 2)?;
let mut rem = Duration::new(0, 0);
let res = wait::sleep(Duration::from_nanos(args[0] as u64), &mut rem);
if res == Err(Errno::Interrupt) {
warnln!("Sleep interrupted, {:?} remaining", rem);
if rem_buf.is_some() {
todo!()
if let Some(rem_buf) = rem_buf {
rem_buf[0] = rem.as_secs();
rem_buf[1] = rem.subsec_nanos() as u64;
}
}
res.map(|_| 0)