1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#![allow(unused)]

use crate::exec::interrupt::InterruptStack::Kernel;
use crate::exec::process::{self, ProcessInternal};
use crate::mem::boxed::Box;

pub struct InterruptHandler {
    process: &'static ProcessInternal,
    handler: &'static mut dyn FnMut(&Context),
    stack: InterruptStack,
    irqn: [Option<u16>; 16],
}

impl InterruptHandler {
    pub fn new(context: &process::Context) -> InterruptBuilder {
        InterruptBuilder::new(context.process())
    }

    pub(crate) fn interrupts(&self) -> &[Option<u16>; 16] {
        &self.irqn
    }

    pub(crate) fn contains_interrupt(&self, irqn: u16) -> bool {
        for i in self.irqn.iter() {
            if *i == Some(irqn) {
                return true;
            }
        }

        false
    }

    pub(crate) fn call(&mut self, irqn: u16) {
        (self.handler)(&Context::new(irqn));
    }
}

pub struct Context {
    irqn: u16,
}

impl Context {
    fn new(irqn: u16) -> Context {
        Context {
            irqn
        }
    }

    pub fn irqn(&self) -> u16 {
        self.irqn
    }
}

#[derive(Copy, Clone, PartialEq)]
pub enum InterruptStack {
    Kernel,
    //Process,
}

pub struct InterruptBuilder {
    process: &'static ProcessInternal,
    stack: Option<InterruptStack>,
    irqn: [Option<u16>; 16],
}

impl InterruptBuilder {
    fn new(process: &'static ProcessInternal) -> Self {
        InterruptBuilder {
            process,
            stack: None,
            irqn: [None; 16],
        }
    }

    pub fn stack(&mut self, stack: InterruptStack) -> &mut Self {
        self.stack = Some(stack);
        self
    }

    pub fn connect_interrupt(&mut self, irqn: u16) -> &mut Self {
        for i in self.irqn.iter_mut() {
            if i.is_none() {
                *i = Some(irqn);
                break;
            }
        }

        self
    }

    pub fn handler<F>(&mut self, handler: F)
        where F: 'static + FnMut(&Context)
    {
        if self.stack == Some(Kernel) {
            let mut boxed_handler = match Box::try_new_in(handler, self.process.allocator()) {
                Ok(b) => b,
                Err(_) => { return; }
            };

            // todo: introduce lifetime and deallocation
            let handler_runnable = &mut *boxed_handler as *mut _;
            Box::leak(boxed_handler);
            self.build(unsafe { &mut *handler_runnable });
        }
    }


    pub(crate) fn build(&mut self, handler: &'static mut dyn FnMut(&Context)) {
        // Note(unsafe): The stack type is checked before this function call.
        let interrupt = InterruptHandler {
            process: self.process,
            handler,
            stack: unsafe { self.stack.unwrap_unchecked() },
            irqn: self.irqn,
        };
            
        crate::sched::interrupt_handler_add(interrupt);
    }
}