parent
0d1afaa016
commit
b49211f24e
6
Makefile
6
Makefile
|
@ -64,6 +64,11 @@ else
|
||||||
ifneq ($(kvm),no)
|
ifneq ($(kvm),no)
|
||||||
QEMUFLAGS+=-enable-kvm -cpu host
|
QEMUFLAGS+=-enable-kvm -cpu host
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(net),no)
|
||||||
|
QEMUFLAGS+=-net none
|
||||||
|
else
|
||||||
|
QEMUFLAGS+=-net nic,model=e1000 -net user -net dump,file=$(KBUILD)/network.pcap
|
||||||
|
endif
|
||||||
ifeq ($(storage),usb)
|
ifeq ($(storage),usb)
|
||||||
QEMUFLAGS+=-device usb-ehci,id=flash_bus -drive id=flash_drive,file=$(KBUILD)/harddrive.bin,format=raw,if=none -device usb-storage,drive=flash_drive,bus=flash_bus.0
|
QEMUFLAGS+=-device usb-ehci,id=flash_bus -drive id=flash_drive,file=$(KBUILD)/harddrive.bin,format=raw,if=none -device usb-storage,drive=flash_drive,bus=flash_bus.0
|
||||||
else
|
else
|
||||||
|
@ -226,6 +231,7 @@ filesystem/bin/%: schemes/%/Cargo.toml schemes/%/src/** $(BUILD)/libstd.rlib
|
||||||
rm $@.d
|
rm $@.d
|
||||||
|
|
||||||
drivers: \
|
drivers: \
|
||||||
|
filesystem/bin/e1000d \
|
||||||
filesystem/bin/ps2d \
|
filesystem/bin/ps2d \
|
||||||
filesystem/bin/vesad
|
filesystem/bin/vesad
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "*"
|
bitflags = "*"
|
||||||
|
dma = { path = "../dma/" }
|
||||||
io = { path = "../io/" }
|
io = { path = "../io/" }
|
||||||
spin = "*"
|
spin = "*"
|
||||||
syscall = { path = "../../syscall/" }
|
syscall = { path = "../../syscall/" }
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use dma::Dma;
|
||||||
use syscall::error::Result;
|
use syscall::error::Result;
|
||||||
|
|
||||||
use super::dma::Dma;
|
|
||||||
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
|
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
|
||||||
|
|
||||||
pub struct Disk {
|
pub struct Disk {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use io::{Io, Mmio};
|
|
||||||
|
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::{ptr, u32};
|
use std::{ptr, u32};
|
||||||
|
|
||||||
|
use dma::Dma;
|
||||||
|
use io::{Io, Mmio};
|
||||||
use syscall::error::{Error, Result, EIO};
|
use syscall::error::{Error, Result, EIO};
|
||||||
|
|
||||||
use super::dma::Dma;
|
|
||||||
use super::fis::{FisType, FisRegH2D};
|
use super::fis::{FisType, FisRegH2D};
|
||||||
|
|
||||||
const ATA_CMD_READ_DMA_EXT: u8 = 0x25;
|
const ATA_CMD_READ_DMA_EXT: u8 = 0x25;
|
||||||
|
|
|
@ -4,7 +4,6 @@ use self::disk::Disk;
|
||||||
use self::hba::{HbaMem, HbaPortType};
|
use self::hba::{HbaMem, HbaPortType};
|
||||||
|
|
||||||
pub mod disk;
|
pub mod disk;
|
||||||
pub mod dma;
|
|
||||||
pub mod fis;
|
pub mod fis;
|
||||||
pub mod hba;
|
pub mod hba;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
extern crate dma;
|
||||||
extern crate io;
|
extern crate io;
|
||||||
extern crate spin;
|
extern crate spin;
|
||||||
extern crate syscall;
|
extern crate syscall;
|
||||||
|
|
6
drivers/dma/Cargo.toml
Normal file
6
drivers/dma/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "dma"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syscall = { path = "../../syscall/" }
|
|
@ -1,7 +1,11 @@
|
||||||
|
#![feature(question_mark)]
|
||||||
|
|
||||||
|
extern crate syscall;
|
||||||
|
|
||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use syscall::{self, Result};
|
use syscall::Result;
|
||||||
|
|
||||||
struct PhysBox {
|
struct PhysBox {
|
||||||
address: usize,
|
address: usize,
|
10
drivers/e1000d/Cargo.toml
Normal file
10
drivers/e1000d/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "rtl8139d"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags = "*"
|
||||||
|
dma = { path = "../dma/" }
|
||||||
|
io = { path = "../io/" }
|
||||||
|
spin = "*"
|
||||||
|
syscall = { path = "../../syscall/" }
|
41
drivers/e1000d/src/main.rs
Normal file
41
drivers/e1000d/src/main.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
extern crate dma;
|
||||||
|
extern crate syscall;
|
||||||
|
|
||||||
|
use std::{env, thread};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use syscall::{iopl, physmap, physunmap, Packet, MAP_WRITE};
|
||||||
|
|
||||||
|
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 {
|
||||||
|
iopl(3).expect("e1000d: failed to get I/O permission");
|
||||||
|
asm!("cli" :::: "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("e1000d: failed to map address") };
|
||||||
|
{
|
||||||
|
println!("e1000d {:X}", bar);
|
||||||
|
let mut socket = File::create(":network").expect("e1000d: failed to create network scheme");
|
||||||
|
//let scheme = DiskScheme::new(ahci::disks(address, irq));
|
||||||
|
loop {
|
||||||
|
let mut packet = Packet::default();
|
||||||
|
socket.read(&mut packet).expect("e1000d: failed to read network scheme");
|
||||||
|
//scheme.handle(&mut packet);
|
||||||
|
socket.write(&mut packet).expect("e1000d: failed to read network scheme");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe { let _ = physunmap(address); }
|
||||||
|
});
|
||||||
|
}
|
|
@ -36,6 +36,15 @@ pub fn keyboard() {
|
||||||
rshift = pressed;
|
rshift = pressed;
|
||||||
} else if pressed {
|
} else if pressed {
|
||||||
match scancode {
|
match scancode {
|
||||||
|
f @ 0x3B ... 0x44 => { // F1 through F10
|
||||||
|
input.write(&[(f - 0x3B) + 0xF4]).unwrap();
|
||||||
|
},
|
||||||
|
0x57 => { // F11
|
||||||
|
input.write(&[0xFE]).unwrap();
|
||||||
|
},
|
||||||
|
0x58 => { // F12
|
||||||
|
input.write(&[0xFF]).unwrap();
|
||||||
|
},
|
||||||
0x47 => { // Home
|
0x47 => { // Home
|
||||||
input.write(b"\x1B[H").unwrap();
|
input.write(b"\x1B[H").unwrap();
|
||||||
},
|
},
|
||||||
|
@ -69,7 +78,7 @@ pub fn keyboard() {
|
||||||
_ => {
|
_ => {
|
||||||
let c = if ctrl {
|
let c = if ctrl {
|
||||||
match keymap::get_char(scancode, false) {
|
match keymap::get_char(scancode, false) {
|
||||||
c @ 'a' ... 'z' => (c as u8 - b'a' + b'\x01') as char,
|
c @ 'a' ... 'z' => ((c as u8 - b'a') + b'\x01') as char,
|
||||||
c => c
|
c => c
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,5 +4,8 @@ version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" }
|
ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" }
|
||||||
rusttype = { git = "https://github.com/dylanede/rusttype.git" }
|
rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true }
|
||||||
syscall = { path = "../../syscall/" }
|
syscall = { path = "../../syscall/" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
|
3
drivers/vesad/src/console.rs
Normal file
3
drivers/vesad/src/console.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub struct Text {
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
#[cfg(feature="rusttype")]
|
#[cfg(feature="rusttype")]
|
||||||
extern crate rusttype;
|
extern crate rusttype;
|
||||||
|
|
||||||
use std::cmp;
|
use alloc::heap;
|
||||||
|
use std::{cmp, slice};
|
||||||
|
|
||||||
use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64};
|
use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64};
|
||||||
|
|
||||||
|
@ -11,6 +12,15 @@ use self::rusttype::{Font, FontCollection, Scale, point};
|
||||||
#[cfg(not(feature="rusttype"))]
|
#[cfg(not(feature="rusttype"))]
|
||||||
static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font");
|
static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font");
|
||||||
|
|
||||||
|
#[cfg(feature="rusttype")]
|
||||||
|
static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf");
|
||||||
|
#[cfg(feature="rusttype")]
|
||||||
|
static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf");
|
||||||
|
#[cfg(feature="rusttype")]
|
||||||
|
static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf");
|
||||||
|
#[cfg(feature="rusttype")]
|
||||||
|
static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf");
|
||||||
|
|
||||||
/// A display
|
/// A display
|
||||||
#[cfg(not(feature="rusttype"))]
|
#[cfg(not(feature="rusttype"))]
|
||||||
pub struct Display {
|
pub struct Display {
|
||||||
|
@ -39,26 +49,32 @@ pub struct Display {
|
||||||
|
|
||||||
impl Display {
|
impl Display {
|
||||||
#[cfg(not(feature="rusttype"))]
|
#[cfg(not(feature="rusttype"))]
|
||||||
pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display {
|
pub fn new(width: usize, height: usize, onscreen: usize) -> Display {
|
||||||
|
let size = width * height;
|
||||||
|
let offscreen = unsafe { heap::allocate(size * 4, 4096) };
|
||||||
|
unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
|
||||||
Display {
|
Display {
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
onscreen: onscreen,
|
onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
|
||||||
offscreen: offscreen
|
offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature="rusttype")]
|
#[cfg(feature="rusttype")]
|
||||||
pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display {
|
pub fn new(width: usize, height: usize, onscreen: usize) -> Display {
|
||||||
|
let size = width * height;
|
||||||
|
let offscreen = unsafe { heap::allocate(size * 4, 4096) };
|
||||||
|
unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
|
||||||
Display {
|
Display {
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
onscreen: onscreen,
|
onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
|
||||||
offscreen: offscreen,
|
offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) },
|
||||||
font: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono.ttf")).into_font().unwrap(),
|
font: FontCollection::from_bytes(FONT).into_font().unwrap(),
|
||||||
font_bold: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf")).into_font().unwrap(),
|
font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(),
|
||||||
font_bold_italic: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf")).into_font().unwrap(),
|
font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(),
|
||||||
font_italic: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf")).into_font().unwrap()
|
font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,200 +4,22 @@
|
||||||
#![feature(question_mark)]
|
#![feature(question_mark)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate ransid;
|
|
||||||
extern crate syscall;
|
extern crate syscall;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::{BTreeSet, VecDeque};
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::{slice, thread};
|
use std::thread;
|
||||||
use ransid::{Console, Event};
|
use syscall::{physmap, physunmap, Packet, Scheme, MAP_WRITE, MAP_WRITE_COMBINE};
|
||||||
use syscall::{physmap, physunmap, Packet, Result, Scheme, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE};
|
|
||||||
|
|
||||||
use display::Display;
|
|
||||||
use mode_info::VBEModeInfo;
|
use mode_info::VBEModeInfo;
|
||||||
use primitive::fast_set64;
|
use primitive::fast_set64;
|
||||||
|
use scheme::DisplayScheme;
|
||||||
|
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod mode_info;
|
pub mod mode_info;
|
||||||
pub mod primitive;
|
pub mod primitive;
|
||||||
|
pub mod scheme;
|
||||||
struct DisplayScheme {
|
pub mod screen;
|
||||||
console: RefCell<Console>,
|
|
||||||
display: RefCell<Display>,
|
|
||||||
changed: RefCell<BTreeSet<usize>>,
|
|
||||||
input: RefCell<VecDeque<u8>>,
|
|
||||||
end_of_input: RefCell<bool>,
|
|
||||||
cooked: RefCell<VecDeque<u8>>,
|
|
||||||
requested: RefCell<usize>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DisplayScheme {
|
|
||||||
fn event(&self, event: Event) {
|
|
||||||
let mut display = self.display.borrow_mut();
|
|
||||||
let mut changed = self.changed.borrow_mut();
|
|
||||||
|
|
||||||
match event {
|
|
||||||
Event::Char { x, y, c, color, bold, .. } => {
|
|
||||||
display.char(x * 8, y * 16, c, color.data, bold, false);
|
|
||||||
changed.insert(y);
|
|
||||||
},
|
|
||||||
Event::Rect { x, y, w, h, color } => {
|
|
||||||
display.rect(x * 8, y * 16, w * 8, h * 16, color.data);
|
|
||||||
for y2 in y..y + h {
|
|
||||||
changed.insert(y2);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Event::Scroll { rows, color } => {
|
|
||||||
display.scroll(rows * 16, color.data);
|
|
||||||
for y in 0..display.height/16 {
|
|
||||||
changed.insert(y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(&self) {
|
|
||||||
let mut display = self.display.borrow_mut();
|
|
||||||
let mut changed = self.changed.borrow_mut();
|
|
||||||
|
|
||||||
let width = display.width;
|
|
||||||
for change in changed.iter() {
|
|
||||||
display.sync(0, change * 16, width, 16);
|
|
||||||
}
|
|
||||||
changed.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scheme for DisplayScheme {
|
|
||||||
fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
|
||||||
if path == b"input" {
|
|
||||||
Ok(1)
|
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fevent(&self, _id: usize, flags: usize) -> Result<usize> {
|
|
||||||
*self.requested.borrow_mut() = flags;
|
|
||||||
println!("fevent {:X}", flags);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let path_str = if id == 1 {
|
|
||||||
format!("display:input")
|
|
||||||
} else {
|
|
||||||
let console = self.console.borrow();
|
|
||||||
format!("display:{}/{}", console.w, console.h)
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = path_str.as_bytes();
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < buf.len() && i < path.len() {
|
|
||||||
buf[i] = path[i];
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fsync(&self, id: usize) -> Result<usize> {
|
|
||||||
if id == 1 {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
self.sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, _id: usize, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let mut i = 0;
|
|
||||||
let mut input = self.input.borrow_mut();
|
|
||||||
while i < buf.len() && ! input.is_empty() {
|
|
||||||
buf[i] = input.pop_front().unwrap();
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
*self.end_of_input.borrow_mut() = false;
|
|
||||||
}
|
|
||||||
Ok(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
if id == 1 {
|
|
||||||
if self.console.borrow().raw_mode {
|
|
||||||
for &b in buf.iter() {
|
|
||||||
self.input.borrow_mut().push_back(b);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for &b in buf.iter() {
|
|
||||||
match b {
|
|
||||||
b'\x03' => {
|
|
||||||
*self.end_of_input.borrow_mut() = true;
|
|
||||||
self.write(0, b"^C\n")?;
|
|
||||||
},
|
|
||||||
b'\x08' | b'\x7F' => {
|
|
||||||
if let Some(_c) = self.cooked.borrow_mut().pop_back() {
|
|
||||||
self.write(0, b"\x08")?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
b'\n' | b'\r' => {
|
|
||||||
self.cooked.borrow_mut().push_back(b);
|
|
||||||
while let Some(c) = self.cooked.borrow_mut().pop_front() {
|
|
||||||
self.input.borrow_mut().push_back(c);
|
|
||||||
}
|
|
||||||
self.write(0, b"\n")?;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.cooked.borrow_mut().push_back(b);
|
|
||||||
self.write(0, &[b])?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(buf.len())
|
|
||||||
} else {
|
|
||||||
let mut console = self.console.borrow_mut();
|
|
||||||
if console.cursor && console.x < console.w && console.y < console.h {
|
|
||||||
self.event(Event::Rect {
|
|
||||||
x: console.x,
|
|
||||||
y: console.y,
|
|
||||||
w: 1,
|
|
||||||
h: 1,
|
|
||||||
color: console.background
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.write(buf, |event| {
|
|
||||||
self.event(event);
|
|
||||||
});
|
|
||||||
if console.cursor && console.x < console.w && console.y < console.h {
|
|
||||||
self.event(Event::Rect {
|
|
||||||
x: console.x,
|
|
||||||
y: console.y,
|
|
||||||
w: 1,
|
|
||||||
h: 1,
|
|
||||||
color: console.foreground
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ! console.raw_mode {
|
|
||||||
self.sync();
|
|
||||||
}
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&self, _id: usize) -> Result<usize> {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let width;
|
let width;
|
||||||
|
@ -220,58 +42,42 @@ fn main() {
|
||||||
|
|
||||||
let size = width * height;
|
let size = width * height;
|
||||||
|
|
||||||
let onscreen = unsafe { physmap(physbaseptr as usize, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") };
|
let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") };
|
||||||
unsafe { fast_set64(onscreen as *mut u64, 0, size/2) };
|
unsafe { fast_set64(onscreen as *mut u64, 0, size/2) };
|
||||||
|
|
||||||
let offscreen = unsafe { alloc::heap::allocate(size * 4, 4096) };
|
let scheme = DisplayScheme::new(width, height, onscreen);
|
||||||
unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
|
|
||||||
|
|
||||||
let scheme = DisplayScheme {
|
let mut blocked = Vec::new();
|
||||||
console: RefCell::new(Console::new(width/8, height/16)),
|
|
||||||
display: RefCell::new(Display::new(width, height,
|
|
||||||
unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
|
|
||||||
unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }
|
|
||||||
)),
|
|
||||||
changed: RefCell::new(BTreeSet::new()),
|
|
||||||
input: RefCell::new(VecDeque::new()),
|
|
||||||
end_of_input: RefCell::new(false),
|
|
||||||
cooked: RefCell::new(VecDeque::new()),
|
|
||||||
requested: RefCell::new(0)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut blocked = VecDeque::new();
|
|
||||||
loop {
|
loop {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
socket.read(&mut packet).expect("vesad: failed to read display scheme");
|
socket.read(&mut packet).expect("vesad: failed to read display scheme");
|
||||||
//println!("vesad: {:?}", packet);
|
//println!("vesad: {:?}", packet);
|
||||||
|
|
||||||
// If it is a read packet, and there is no data, block it. Otherwise, handle packet
|
// If it is a read packet, and there is no data, block it. Otherwise, handle packet
|
||||||
let mut block = false;
|
if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) {
|
||||||
if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.input.borrow().is_empty() {
|
blocked.push(packet);
|
||||||
if ! *scheme.end_of_input.borrow() {
|
|
||||||
block = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if block {
|
|
||||||
blocked.push_back(packet);
|
|
||||||
} else {
|
} else {
|
||||||
scheme.handle(&mut packet);
|
scheme.handle(&mut packet);
|
||||||
socket.write(&packet).expect("vesad: failed to write display scheme");
|
socket.write(&packet).expect("vesad: failed to write display scheme");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are blocked readers, and data is available, handle them
|
// If there are blocked readers, and data is available, handle them
|
||||||
while ! scheme.input.borrow().is_empty() || *scheme.end_of_input.borrow() {
|
{
|
||||||
if let Some(mut packet) = blocked.pop_front() {
|
let mut i = 0;
|
||||||
scheme.handle(&mut packet);
|
while i < blocked.len() {
|
||||||
socket.write(&packet).expect("vesad: failed to write display scheme");
|
if ! scheme.will_block(blocked[i].b) {
|
||||||
} else {
|
let mut packet = blocked.remove(i);
|
||||||
break;
|
scheme.handle(&mut packet);
|
||||||
|
socket.write(&packet).expect("vesad: failed to write display scheme");
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are requested events, and data is available, send a notification
|
// If there are requested events, and data is available, send a notification
|
||||||
if (! scheme.input.borrow().is_empty() || *scheme.end_of_input.borrow()) && *scheme.requested.borrow() & EVENT_READ == EVENT_READ {
|
/* TODO
|
||||||
|
if (! scheme.screen.borrow().input.is_empty() || scheme.screen.borrow().end_of_input) && scheme.screen.borrow().requested & EVENT_READ == EVENT_READ {
|
||||||
let event_packet = Packet {
|
let event_packet = Packet {
|
||||||
id: 0,
|
id: 0,
|
||||||
pid: 0,
|
pid: 0,
|
||||||
|
@ -280,10 +86,11 @@ fn main() {
|
||||||
a: syscall::number::SYS_FEVENT,
|
a: syscall::number::SYS_FEVENT,
|
||||||
b: 0,
|
b: 0,
|
||||||
c: EVENT_READ,
|
c: EVENT_READ,
|
||||||
d: scheme.input.borrow().len()
|
d: scheme.screen.borrow().input.len()
|
||||||
};
|
};
|
||||||
socket.write(&event_packet).expect("vesad: failed to write display scheme");
|
socket.write(&event_packet).expect("vesad: failed to write display scheme");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
143
drivers/vesad/src/scheme.rs
Normal file
143
drivers/vesad/src/scheme.rs
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
use syscall::{Result, Error, EBADF, ENOENT, Scheme};
|
||||||
|
|
||||||
|
use display::Display;
|
||||||
|
use screen::TextScreen;
|
||||||
|
|
||||||
|
pub struct DisplayScheme {
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
onscreen: usize,
|
||||||
|
active: Cell<usize>,
|
||||||
|
screens: RefCell<BTreeMap<usize, TextScreen>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayScheme {
|
||||||
|
pub fn new(width: usize, height: usize, onscreen: usize) -> DisplayScheme {
|
||||||
|
let mut screens = BTreeMap::new();
|
||||||
|
for i in 1..7 {
|
||||||
|
screens.insert(i, TextScreen::new(Display::new(width, height, onscreen)));
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayScheme {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
onscreen: onscreen,
|
||||||
|
active: Cell::new(1),
|
||||||
|
screens: RefCell::new(screens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn will_block(&self, id: usize) -> bool {
|
||||||
|
let screens = self.screens.borrow();
|
||||||
|
if let Some(screen) = screens.get(&id) {
|
||||||
|
screen.will_block()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scheme for DisplayScheme {
|
||||||
|
fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
||||||
|
if path == b"input" {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
let path_str = str::from_utf8(path).unwrap_or("");
|
||||||
|
let id = path_str.parse::<usize>().unwrap_or(0);
|
||||||
|
if self.screens.borrow().contains_key(&id) {
|
||||||
|
Ok(id)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(ENOENT))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dup(&self, id: usize) -> Result<usize> {
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fevent(&self, id: usize, flags: usize) -> Result<usize> {
|
||||||
|
let mut screens = self.screens.borrow_mut();
|
||||||
|
if let Some(mut screen) = screens.get_mut(&id) {
|
||||||
|
println!("fevent {:X}", flags);
|
||||||
|
screen.requested = flags;
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EBADF))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let screens = self.screens.borrow();
|
||||||
|
let path_str = if id == 0 {
|
||||||
|
format!("display:input")
|
||||||
|
} else if let Some(screen) = screens.get(&id) {
|
||||||
|
format!("display:{}/{}/{}", id, screen.console.w, screen.console.h)
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(EBADF));
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = path_str.as_bytes();
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < path.len() {
|
||||||
|
buf[i] = path[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(&self, id: usize) -> Result<usize> {
|
||||||
|
let mut screens = self.screens.borrow_mut();
|
||||||
|
if let Some(mut screen) = screens.get_mut(&id) {
|
||||||
|
if id == self.active.get() {
|
||||||
|
screen.sync();
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EBADF))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let mut screens = self.screens.borrow_mut();
|
||||||
|
if let Some(mut screen) = screens.get_mut(&id) {
|
||||||
|
screen.read(buf)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EBADF))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
let mut screens = self.screens.borrow_mut();
|
||||||
|
if id == 0 {
|
||||||
|
if buf.len() == 1 && buf[0] >= 0xF4 {
|
||||||
|
let new_active = (buf[0] - 0xF4) as usize + 1;
|
||||||
|
if let Some(mut screen) = screens.get_mut(&new_active) {
|
||||||
|
self.active.set(new_active);
|
||||||
|
screen.redraw();
|
||||||
|
}
|
||||||
|
Ok(1)
|
||||||
|
} else {
|
||||||
|
if let Some(mut screen) = screens.get_mut(&self.active.get()) {
|
||||||
|
screen.input(buf)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EBADF))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(mut screen) = screens.get_mut(&id) {
|
||||||
|
screen.write(buf, id == self.active.get())
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EBADF))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&self, _id: usize) -> Result<usize> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
1
drivers/vesad/src/screen/graphic.rs
Normal file
1
drivers/vesad/src/screen/graphic.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub struct GraphicScreen;
|
10
drivers/vesad/src/screen/mod.rs
Normal file
10
drivers/vesad/src/screen/mod.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
pub use self::graphic::GraphicScreen;
|
||||||
|
pub use self::text::TextScreen;
|
||||||
|
|
||||||
|
mod graphic;
|
||||||
|
mod text;
|
||||||
|
|
||||||
|
pub enum Screen {
|
||||||
|
Graphic(GraphicScreen),
|
||||||
|
Text(TextScreen)
|
||||||
|
}
|
149
drivers/vesad/src/screen/text.rs
Normal file
149
drivers/vesad/src/screen/text.rs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
extern crate ransid;
|
||||||
|
|
||||||
|
use std::collections::{BTreeSet, VecDeque};
|
||||||
|
|
||||||
|
use self::ransid::{Console, Event};
|
||||||
|
use syscall::Result;
|
||||||
|
|
||||||
|
use display::Display;
|
||||||
|
|
||||||
|
pub struct TextScreen {
|
||||||
|
pub console: Console,
|
||||||
|
pub display: Display,
|
||||||
|
pub changed: BTreeSet<usize>,
|
||||||
|
pub input: VecDeque<u8>,
|
||||||
|
pub end_of_input: bool,
|
||||||
|
pub cooked: VecDeque<u8>,
|
||||||
|
pub requested: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextScreen {
|
||||||
|
pub fn new(display: Display) -> TextScreen {
|
||||||
|
TextScreen {
|
||||||
|
console: Console::new(display.width/8, display.height/16),
|
||||||
|
display: display,
|
||||||
|
changed: BTreeSet::new(),
|
||||||
|
input: VecDeque::new(),
|
||||||
|
end_of_input: false,
|
||||||
|
cooked: VecDeque::new(),
|
||||||
|
requested: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
if self.console.raw_mode {
|
||||||
|
for &b in buf.iter() {
|
||||||
|
self.input.push_back(b);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for &b in buf.iter() {
|
||||||
|
match b {
|
||||||
|
b'\x03' => {
|
||||||
|
self.end_of_input = true;
|
||||||
|
self.write(b"^C\n", true)?;
|
||||||
|
},
|
||||||
|
b'\x08' | b'\x7F' => {
|
||||||
|
if let Some(_c) = self.cooked.pop_back() {
|
||||||
|
self.write(b"\x08", true)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
b'\n' | b'\r' => {
|
||||||
|
self.cooked.push_back(b);
|
||||||
|
while let Some(c) = self.cooked.pop_front() {
|
||||||
|
self.input.push_back(c);
|
||||||
|
}
|
||||||
|
self.write(b"\n", true)?;
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
self.cooked.push_back(b);
|
||||||
|
self.write(&[b], true)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
while i < buf.len() && ! self.input.is_empty() {
|
||||||
|
buf[i] = self.input.pop_front().unwrap();
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
self.end_of_input = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn will_block(&self) -> bool {
|
||||||
|
self.input.is_empty() && ! self.end_of_input
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
|
||||||
|
if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
|
||||||
|
let x = self.console.x;
|
||||||
|
let y = self.console.y;
|
||||||
|
let color = self.console.background;
|
||||||
|
self.display.rect(x * 8, y * 16, 8, 16, color.data);
|
||||||
|
self.changed.insert(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let display = &mut self.display;
|
||||||
|
let changed = &mut self.changed;
|
||||||
|
self.console.write(buf, |event| {
|
||||||
|
match event {
|
||||||
|
Event::Char { x, y, c, color, bold, .. } => {
|
||||||
|
display.char(x * 8, y * 16, c, color.data, bold, false);
|
||||||
|
changed.insert(y);
|
||||||
|
},
|
||||||
|
Event::Rect { x, y, w, h, color } => {
|
||||||
|
display.rect(x * 8, y * 16, w * 8, h * 16, color.data);
|
||||||
|
for y2 in y..y + h {
|
||||||
|
changed.insert(y2);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Event::Scroll { rows, color } => {
|
||||||
|
display.scroll(rows * 16, color.data);
|
||||||
|
for y in 0..display.height/16 {
|
||||||
|
changed.insert(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
|
||||||
|
let x = self.console.x;
|
||||||
|
let y = self.console.y;
|
||||||
|
let color = self.console.foreground;
|
||||||
|
self.display.rect(x * 8, y * 16, 8, 16, color.data);
|
||||||
|
self.changed.insert(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! self.console.raw_mode && sync {
|
||||||
|
self.sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sync(&mut self) {
|
||||||
|
let width = self.display.width;
|
||||||
|
for change in self.changed.iter() {
|
||||||
|
self.display.sync(0, change * 16, width, 16);
|
||||||
|
}
|
||||||
|
self.changed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn redraw(&mut self) {
|
||||||
|
let width = self.display.width;
|
||||||
|
let height = self.display.height;
|
||||||
|
self.display.sync(0, 0, width, height);
|
||||||
|
self.changed.clear();
|
||||||
|
}
|
||||||
|
}
|
6
filesystem/etc/pcid.toml
Normal file
6
filesystem/etc/pcid.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[[drivers]]
|
||||||
|
name = "E1000 NIC"
|
||||||
|
class = 2
|
||||||
|
vendor = 32902
|
||||||
|
device = 4110
|
||||||
|
command = ["file:bin/e1000d", "$BAR0", "$IRQ"]
|
|
@ -1,5 +1,11 @@
|
||||||
initfs:bin/pcid initfs:etc/pcid.toml
|
initfs:bin/pcid initfs:etc/pcid.toml
|
||||||
initfs:bin/redoxfs disk:0
|
initfs:bin/redoxfs disk:0
|
||||||
|
initfs:bin/pcid file:etc/pcid.toml
|
||||||
file:bin/vesad
|
file:bin/vesad
|
||||||
file:bin/ps2d
|
file:bin/ps2d
|
||||||
file:bin/getty display:
|
file:bin/getty display:1
|
||||||
|
file:bin/getty display:2
|
||||||
|
file:bin/getty display:3
|
||||||
|
file:bin/getty display:4
|
||||||
|
file:bin/getty display:5
|
||||||
|
file:bin/getty display:6
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit b7915192616f3ab058638c10fbfe84d9bcda2008
|
Subproject commit db8e494fda926c1bec3c283edeab90db83ca3539
|
|
@ -1 +1 @@
|
||||||
Subproject commit eaf26765c12efe5519fb2af72557dc0ee8286bcd
|
Subproject commit 17896532dc139fcc42237effbb7e90cf5bb95702
|
Loading…
Reference in a new issue