mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: kernel/objects/endpoint: wire up syscall
This commit is contained in:
parent
e6d6a2ee21
commit
86dbca7ef5
@ -1,10 +1,12 @@
|
||||
use crate::{
|
||||
objects::*,
|
||||
plat::{irq::IRQ_NUM, trap::TrapContextOps},
|
||||
use crate::objects::*;
|
||||
use crate::plat::{
|
||||
irq::{IRQ_MANAGER, IRQ_NUM},
|
||||
trap::TrapContextOps,
|
||||
};
|
||||
use core::{cmp::min, fmt::Debug};
|
||||
use tcb::{ThreadState, EP_QUEUE_LINK_ID};
|
||||
use uapi::{cap::ObjectType, syscall::*};
|
||||
use utils::then::Then;
|
||||
use utils::{addr::*, array::*, linked_list::Link};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@ -35,8 +37,8 @@ impl KernelObject for EndpointObject {
|
||||
* > | [63:0] |
|
||||
*
|
||||
* in our implementation, EndpointCap layout:
|
||||
* > args[0]: badge
|
||||
* > args[1]: none
|
||||
* > args[0]: option<irq>
|
||||
* > args[1]: badge
|
||||
* > ptr: base_ptr
|
||||
* > cap_type: cap_tag
|
||||
*/
|
||||
@ -45,15 +47,16 @@ pub type EndpointCap<'a> = Cap<'a, EndpointObject>;
|
||||
|
||||
impl<'a> EndpointCap<'a> {
|
||||
pub fn mint(ptr: PhysAddr, badge: usize) -> RawCap {
|
||||
RawCap::new(badge, 0, ptr, ObjectType::Endpoint)
|
||||
RawCap::new(0, badge, ptr, ObjectType::Endpoint)
|
||||
}
|
||||
|
||||
pub fn can_send(&self) -> bool {
|
||||
self.cap().get().args[0] & 0x2 != 0
|
||||
pub fn irqs(&self) -> Option<usize> {
|
||||
let irqs = self.cap().get().args[0];
|
||||
(irqs != 0).then_some(irqs)
|
||||
}
|
||||
|
||||
pub fn can_recv(&self) -> bool {
|
||||
self.cap().get().args[0] & 0x1 != 0
|
||||
fn set_irq(&mut self, irqs: usize) {
|
||||
self.cap().get().args[0] |= 1 << irqs;
|
||||
}
|
||||
|
||||
pub fn badge(&self) -> usize {
|
||||
@ -64,8 +67,8 @@ impl<'a> EndpointCap<'a> {
|
||||
self.as_object().signals
|
||||
}
|
||||
|
||||
pub fn set_signals(&mut self, signals: usize) {
|
||||
self.as_object_mut().signals = signals;
|
||||
fn set_signals(&mut self, signals: usize) {
|
||||
self.as_object_mut().signals = signals & self.irqs().unwrap_or(0);
|
||||
}
|
||||
|
||||
pub fn state(&self) -> EndpointState {
|
||||
@ -84,6 +87,20 @@ impl<'a> EndpointCap<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_set_irq(&mut self, tcb: &TcbObject) -> SysResult {
|
||||
let irq = tcb.trapframe.get_reg(REG_ARG_0);
|
||||
IRQ_MANAGER.lock().enable(irq, self.cte.clone());
|
||||
self.set_irq(irq);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn do_ack_irq(&mut self, tcb: &TcbObject) -> SysResult {
|
||||
let irq = tcb.trapframe.get_reg(REG_ARG_0);
|
||||
(self.irqs().unwrap_or(0) & (1 << irq) != 0).else_err((), SysError::InvalidArgument)?;
|
||||
IRQ_MANAGER.lock().complete(irq);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult {
|
||||
match self.state() {
|
||||
EndpointState::Recv => {
|
||||
@ -148,8 +165,9 @@ impl<'a> EndpointCap<'a> {
|
||||
let state = self.state();
|
||||
|
||||
self.set_signals(signals);
|
||||
let signals = self.signals(); // set_signals will filter out invalid signals
|
||||
|
||||
if state == EndpointState::Recv {
|
||||
if state == EndpointState::Recv && signals != 0 {
|
||||
// do recv immediately
|
||||
self.set_signals(0);
|
||||
|
||||
@ -170,8 +188,8 @@ impl Debug for EndpointCap<'_> {
|
||||
f.debug_struct("EndpointCap")
|
||||
.field("ptr", &self.cap().get().ptr)
|
||||
.field("badge", &self.badge())
|
||||
.field("can_send", &self.can_send())
|
||||
.field("can_recv", &self.can_recv())
|
||||
.field("irqs", &self.irqs())
|
||||
.field("signals", &self.signals())
|
||||
.field("state", &self.state())
|
||||
.finish()
|
||||
}
|
||||
|
@ -50,7 +50,6 @@ pub fn set_irq_driver(driver: IrqDriver) {
|
||||
|
||||
pub struct IrqManager {
|
||||
handler: [CapEntry; IRQ_NUM],
|
||||
state: [IrqState; IRQ_NUM],
|
||||
}
|
||||
|
||||
pub static IRQ_MANAGER: Lazy<Mutex<IrqManager>> = Lazy::new(|| Mutex::new(IrqManager::new()));
|
||||
@ -59,10 +58,31 @@ impl IrqManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
handler: core::array::from_fn::<_, IRQ_NUM, _>(|_| CapEntry::new(NullCap::mint())),
|
||||
state: [IrqState::Inactive; IRQ_NUM],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable(&mut self, irq: usize, cap: CapEntry) {
|
||||
if irq >= IRQ_NUM {
|
||||
error!("[IrqManager] Invalid IRQ number: {}", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
if NullCap::try_from(&self.handler[irq]).is_ok() {
|
||||
self.handler[irq] = cap;
|
||||
IRQ_DRIVER.lock().complete(irq);
|
||||
IRQ_DRIVER.lock().enable(irq);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn complete(&mut self, irq: usize) {
|
||||
if irq >= IRQ_NUM {
|
||||
error!("[IrqManager] Invalid IRQ number: {}", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_DRIVER.lock().complete(irq);
|
||||
}
|
||||
|
||||
pub fn dispatch(&mut self) {
|
||||
let irq = IRQ_DRIVER.lock().claim();
|
||||
if irq.is_none() {
|
||||
@ -70,31 +90,16 @@ impl IrqManager {
|
||||
return;
|
||||
}
|
||||
|
||||
let irq = irq.unwrap();
|
||||
if irq >= IRQ_NUM {
|
||||
error!("[IrqManager] Invalid IRQ number: {}", irq);
|
||||
IRQ_DRIVER.lock().disable(irq);
|
||||
IRQ_DRIVER.lock().complete(irq);
|
||||
return;
|
||||
}
|
||||
|
||||
match self.state[irq] {
|
||||
IrqState::Inactive => {
|
||||
warn!("[IrqManager] Received disabled IRQ: {}", irq);
|
||||
IRQ_DRIVER.lock().disable(irq);
|
||||
},
|
||||
IrqState::Signal => {
|
||||
if let Some(irq) = irq
|
||||
&& irq < IRQ_NUM
|
||||
&& let Ok(mut cap) = EndpointCap::try_from(&self.handler[irq])
|
||||
{
|
||||
trace!("[IrqManager] Dispatching IRQ: {}", irq);
|
||||
let mut cap = EndpointCap::try_from(&self.handler[irq]).unwrap();
|
||||
cap.do_signal(irq).unwrap();
|
||||
return;
|
||||
},
|
||||
IrqState::Ipi => {
|
||||
todo!("Kernel: NO SMP support now");
|
||||
},
|
||||
IrqState::Reserved => error!("[IrqManager] Received unhandled reserved IRQ: {}", irq),
|
||||
} else {
|
||||
warn!("[IrqManager] Received invalid IRQ: {:?}", irq);
|
||||
IRQ_DRIVER.lock().disable(irq.unwrap());
|
||||
IRQ_DRIVER.lock().complete(irq.unwrap());
|
||||
}
|
||||
|
||||
IRQ_DRIVER.lock().complete(irq);
|
||||
}
|
||||
}
|
||||
|
@ -56,10 +56,13 @@ pub fn handle_syscall(tcb: &mut TcbObject) -> SysResult {
|
||||
cap.do_recv(tcb)
|
||||
},
|
||||
Syscall::IrqSet => {
|
||||
unimplemented!("[Syscall] IrqSet: {:?}", info.label())
|
||||
assert_length!(info, 3);
|
||||
let mut cap = EndpointCap::try_from(cap)?;
|
||||
cap.do_set_irq(tcb)
|
||||
},
|
||||
Syscall::IrqAck => {
|
||||
unimplemented!("[Syscall] IrqAck: {:?}", info.label())
|
||||
let mut cap = EndpointCap::try_from(cap)?;
|
||||
cap.do_ack_irq(tcb)
|
||||
},
|
||||
_ => todo!("[Syscall] unhandled syscall: {:?}, {:?}", info.label(), cap),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user