main.rs 3.39 KB
Newer Older
Jeremy Soller's avatar
Jeremy Soller committed
1 2 3
#![feature(asm)]

extern crate dma;
Jeremy Soller's avatar
Jeremy Soller committed
4
extern crate event;
Jeremy Soller's avatar
Jeremy Soller committed
5 6
extern crate syscall;

Jeremy Soller's avatar
Jeremy Soller committed
7
use std::cell::RefCell;
Jeremy Soller's avatar
Jeremy Soller committed
8 9
use std::{env, thread};
use std::fs::File;
Jeremy Soller's avatar
Jeremy Soller committed
10 11 12
use std::io::{Read, Write, Result};
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
Jeremy Soller's avatar
Jeremy Soller committed
13

Jeremy Soller's avatar
Jeremy Soller committed
14 15 16
use event::EventQueue;
use syscall::{Packet, Scheme, MAP_WRITE};
use syscall::error::EWOULDBLOCK;
17 18

pub mod device;
Jeremy Soller's avatar
Jeremy Soller committed
19 20 21 22 23 24 25 26 27 28 29 30

fn main() {
    let mut args = env::args().skip(1);

    let bar_str = args.next().expect("e1000d: no address provided");
    let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address");

    let irq_str = args.next().expect("e1000d: no irq provided");
    let irq = irq_str.parse::<u8>().expect("e1000d: failed to parse irq");

    thread::spawn(move || {
        unsafe {
Jeremy Soller's avatar
Jeremy Soller committed
31
            syscall::iopl(3).expect("e1000d: failed to get I/O permission");
Jeremy Soller's avatar
Jeremy Soller committed
32 33 34
            asm!("cli" :::: "intel", "volatile");
        }

Jeremy Soller's avatar
Jeremy Soller committed
35 36 37
        let socket = Arc::new(RefCell::new(File::create(":network").expect("e1000d: failed to create network scheme")));

        let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") };
Jeremy Soller's avatar
Jeremy Soller committed
38
        {
Jeremy Soller's avatar
Jeremy Soller committed
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
            let device = Arc::new(unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") });

            let mut event_queue = EventQueue::<()>::new().expect("e1000d: failed to create event queue");

            let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));

            let device_irq = device.clone();
            let socket_irq = socket.clone();
            let todo_irq = todo.clone();
            let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file");
            event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result<Option<()>> {
                let mut irq = [0; 8];
                irq_file.read(&mut irq)?;
                if unsafe { device_irq.irq() } {
                    irq_file.write(&mut irq)?;

                    let mut todo = todo_irq.borrow_mut();
                    let mut i = 0;
                    while i < todo.len() {
                        let a = todo[i].a;
                        device_irq.handle(&mut todo[i]);
                        if todo[i].a == (-EWOULDBLOCK) as usize {
                            todo[i].a = a;
                            i += 1;
                        } else {
                            socket_irq.borrow_mut().write(&mut todo[i])?;
                            todo.remove(i);
                        }
                    }
                }
                Ok(None)
            }).expect("e1000d: failed to catch events on IRQ file");

            let socket_fd = socket.borrow().as_raw_fd();
            event_queue.add(socket_fd, move |_count: usize| -> Result<Option<()>> {
Jeremy Soller's avatar
Jeremy Soller committed
74
                let mut packet = Packet::default();
Jeremy Soller's avatar
Jeremy Soller committed
75 76 77
                socket.borrow_mut().read(&mut packet)?;

                let a = packet.a;
78
                device.handle(&mut packet);
Jeremy Soller's avatar
Jeremy Soller committed
79 80 81 82 83 84 85 86 87 88 89
                if packet.a == (-EWOULDBLOCK) as usize {
                    packet.a = a;
                    todo.borrow_mut().push(packet);
                } else {
                    socket.borrow_mut().write(&mut packet)?;
                }

                Ok(None)
            }).expect("e1000d: failed to catch events on IRQ file");

            event_queue.run().expect("e1000d: failed to handle events");
Jeremy Soller's avatar
Jeremy Soller committed
90
        }
Jeremy Soller's avatar
Jeremy Soller committed
91
        unsafe { let _ = syscall::physunmap(address); }
Jeremy Soller's avatar
Jeremy Soller committed
92 93
    });
}