WIP: VESA driver. Make initfs generated by code

This commit is contained in:
Jeremy Soller 2016-09-20 21:52:45 -06:00
parent a4ede1d23d
commit e110ab81b8
21 changed files with 430 additions and 306 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
Cargo.lock
build
target
initfs/bin

View file

@ -28,7 +28,9 @@ clean:
cargo clean --manifest-path ion/Cargo.toml
cargo clean --manifest-path drivers/ps2d/Cargo.toml
cargo clean --manifest-path drivers/pcid/Cargo.toml
cargo clean --manifest-path drivers/vesad/Cargo.toml
cargo clean --manifest-path schemes/example/Cargo.toml
rm -rf initfs/bin
rm -rf build
FORCE:
@ -123,24 +125,40 @@ $(BUILD)/libstd.rlib: libstd/Cargo.toml libstd/src/** $(BUILD)/libcore.rlib $(BU
$(CARGO) rustc --verbose --manifest-path $< $(CARGOFLAGS) -o $@
cp libstd/target/$(TARGET)/debug/deps/*.rlib $(BUILD)
$(BUILD)/init: init/Cargo.toml init/src/*.rs $(BUILD)/libstd.rlib
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@
$(BUILD)/ion: ion/Cargo.toml ion/src/*.rs $(BUILD)/libstd.rlib
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@
$(BUILD)/pcid: drivers/pcid/Cargo.toml drivers/pcid/src/** $(BUILD)/libstd.rlib
initfs/bin/init: init/Cargo.toml init/src/*.rs $(BUILD)/libstd.rlib
mkdir -p initfs/bin
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@
rm $@.d
$(BUILD)/ps2d: drivers/ps2d/Cargo.toml drivers/ps2d/src/** $(BUILD)/libstd.rlib
initfs/bin/%: drivers/%/Cargo.toml drivers/%/src/** $(BUILD)/libstd.rlib
mkdir -p initfs/bin
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@
rm $@.d
$(BUILD)/example: schemes/example/Cargo.toml schemes/example/src/** $(BUILD)/libstd.rlib
initfs/bin/%: schemes/%/Cargo.toml schemes/%/src/** $(BUILD)/libstd.rlib
mkdir -p initfs/bin
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@
rm $@.d
$(BUILD)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid $(BUILD)/ps2d $(BUILD)/example
$(BUILD)/initfs.rs: \
initfs/bin/init \
initfs/bin/pcid \
initfs/bin/ps2d \
initfs/bin/vesad \
initfs/bin/example
echo 'use collections::BTreeMap;' > $@
echo 'pub fn gen() -> BTreeMap<&'"'"'static [u8], &'"'"'static [u8]> {' >> $@
echo ' let mut files: BTreeMap<&'"'"'static [u8], &'"'"'static [u8]> = BTreeMap::new();' >> $@
find initfs -type f -o -type l | cut -d '/' -f2- | sort \
| awk '{printf(" files.insert(b\"%s\", include_bytes!(\"../../initfs/%s\"));\n", $$0, $$0)}' \
>> $@
echo ' files' >> $@
echo '}' >> $@

View file

@ -6,7 +6,6 @@ version = "0.1.0"
bitflags = "*"
hole_list_allocator = { path = "../../alloc/hole_list_allocator" }
io = { path = "../../drivers/io" }
ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" }
spin = "*"
[dependencies.x86]

View file

@ -1,31 +1,14 @@
use core::fmt::{self, Write};
use spin::Mutex;
use device::display;
use device::serial::COM1;
pub static CONSOLE: Mutex<Console> = Mutex::new(Console::new());
pub static CONSOLE: Mutex<Console> = Mutex::new(Console);
pub struct Console;
impl Console {
const fn new() -> Self {
Console
}
}
impl Write for Console {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
if let Some(ref mut console) = *display::CONSOLE.lock() {
if let Some(ref mut display) = *display::DISPLAY.lock() {
console.write(s.as_bytes(), |event| {
display.event(event);
});
}
Ok(())
} else {
COM1.lock().write_str(s)
}
COM1.lock().write_str(s)
}
}

View file

@ -1,245 +0,0 @@
use core::{cmp, slice};
use ransid::{Console, Event};
use spin::Mutex;
use memory::Frame;
use paging::{ActivePageTable, Page, PhysicalAddress, VirtualAddress, entry};
#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
asm!("cld
rep movsq"
:
: "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
: "cc", "memory"
: "intel", "volatile");
}
#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_set(dst: *mut u32, src: u32, len: usize) {
asm!("cld
rep stosd"
:
: "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len)
: "cc", "memory"
: "intel", "volatile");
}
#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
asm!("cld
rep stosq"
:
: "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
: "cc", "memory"
: "intel", "volatile");
}
/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
attributes: u16,
win_a: u8,
win_b: u8,
granularity: u16,
winsize: u16,
segment_a: u16,
segment_b: u16,
winfuncptr: u32,
bytesperscanline: u16,
pub xresolution: u16,
pub yresolution: u16,
xcharsize: u8,
ycharsize: u8,
numberofplanes: u8,
bitsperpixel: u8,
numberofbanks: u8,
memorymodel: u8,
banksize: u8,
numberofimagepages: u8,
unused: u8,
redmasksize: u8,
redfieldposition: u8,
greenmasksize: u8,
greenfieldposition: u8,
bluemasksize: u8,
bluefieldposition: u8,
rsvdmasksize: u8,
rsvdfieldposition: u8,
directcolormodeinfo: u8,
physbaseptr: u32,
offscreenmemoryoffset: u32,
offscreenmemsize: u16,
}
pub static CONSOLE: Mutex<Option<Console>> = Mutex::new(None);
pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);
static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font");
pub unsafe fn init(active_table: &mut ActivePageTable) {
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);
let mode_info = &*(0x5200 as *const VBEModeInfo);
if mode_info.physbaseptr > 0 {
let width = mode_info.xresolution as usize;
let height = mode_info.yresolution as usize;
let onscreen = mode_info.physbaseptr as usize + ::KERNEL_OFFSET;
let size = width * height;
{
let start_page = Page::containing_address(VirtualAddress::new(onscreen));
let end_page = Page::containing_address(VirtualAddress::new(onscreen + size * 4 - 1));
for page in Page::range_inclusive(start_page, end_page) {
let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get() - ::KERNEL_OFFSET));
active_table.map_to(page, frame, /*actually sets PAT for write combining*/ entry::HUGE_PAGE | entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
}
}
fast_set64(onscreen as *mut u64, 0, size/2);
let offscreen = ::allocator::__rust_allocate(size * 4, 4096);
fast_set64(offscreen as *mut u64, 0, size/2);
*DISPLAY.lock() = Some(Display::new(width, height,
slice::from_raw_parts_mut(onscreen as *mut u32, size),
slice::from_raw_parts_mut(offscreen as *mut u32, size)
));
*CONSOLE.lock() = Some(Console::new(width/8, height/16));
}
active_table.unmap(Page::containing_address(VirtualAddress::new(0x5200)));
}
/// A display
pub struct Display {
pub width: usize,
pub height: usize,
pub onscreen: &'static mut [u32],
pub offscreen: &'static mut [u32],
}
impl Display {
fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display {
Display {
width: width,
height: height,
onscreen: onscreen,
offscreen: offscreen,
}
}
/// Draw a rectangle
fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
let start_y = cmp::min(self.height - 1, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width - 1, x);
let len = cmp::min(self.width, x + w) - start_x;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
onscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
unsafe {
fast_set(offscreen_ptr as *mut u32, color, len);
fast_set(onscreen_ptr as *mut u32, color, len);
}
offscreen_ptr += stride;
onscreen_ptr += stride;
rows -= 1;
}
}
/// Draw a character
fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
if x + 8 <= self.width && y + 16 <= self.height {
let mut font_i = 16 * (character as usize);
let font_end = font_i + 16;
if font_end <= FONT.len() {
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + x * 4;
offscreen_ptr += offset;
onscreen_ptr += offset;
while font_i < font_end {
let mut row_data = FONT[font_i];
let mut col = 8;
while col > 0 {
col -= 1;
if row_data & 1 == 1 {
unsafe {
*((offscreen_ptr + col * 4) as *mut u32) = color;
}
}
row_data = row_data >> 1;
}
unsafe {
fast_copy64(onscreen_ptr as *mut u64, offscreen_ptr as *const u64, 4);
}
offscreen_ptr += stride;
onscreen_ptr += stride;
font_i += 1;
}
}
}
}
/// Scroll display
pub fn scroll(&mut self, rows: usize, color: u32) {
let data = (color as u64) << 32 | color as u64;
let width = self.width/2;
let height = self.height;
if rows > 0 && rows < height {
let off1 = rows * width;
let off2 = height * width - off1;
unsafe {
let data_ptr = self.offscreen.as_mut_ptr() as *mut u64;
fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2);
fast_set64(data_ptr.offset(off2 as isize), data, off1);
fast_copy64(self.onscreen.as_mut_ptr() as *mut u64, data_ptr, off1 + off2);
}
}
}
/// Handle ransid event
pub fn event(&mut self, event: Event) {
match event {
Event::Char { x, y, c, color, .. } => {
self.char(x * 8, y * 16, c, color.data);
},
Event::Rect { x, y, w, h, color } => {
self.rect(x * 8, y * 16, w * 8, h * 16, color.data);
},
Event::Scroll { rows, color } => {
self.scroll(rows * 16, color.data);
}
}
}
}

View file

@ -1,9 +1,5 @@
use paging::ActivePageTable;
pub mod display;
pub mod serial;
pub unsafe fn init(active_table: &mut ActivePageTable){
pub unsafe fn init(){
serial::init();
display::init(active_table);
}

View file

@ -16,7 +16,6 @@ extern crate hole_list_allocator as allocator;
#[macro_use]
extern crate bitflags;
extern crate io;
extern crate ransid;
extern crate spin;
pub extern crate x86;

View file

@ -109,7 +109,7 @@ pub unsafe extern fn kstart() -> ! {
}
// Initialize devices
device::init(&mut active_table);
device::init();
// Send kernel page table to APs
{
@ -136,7 +136,7 @@ pub unsafe extern fn kstart() -> ! {
}
/// Entry to rust for an AP
pub unsafe extern fn kstart_ap(cpu_id: usize, page_table: usize, stack_start: usize, stack_end: usize) -> ! {
pub unsafe extern fn kstart_ap(cpu_id: usize, _page_table: usize, stack_start: usize, stack_end: usize) -> ! {
{
assert_eq!(BSS_TEST_ZERO, 0);
assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);

6
drivers/vesad/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "vesad"
version = "0.1.0"
[dependencies]
syscall = { path = "../../syscall/" }

View file

@ -0,0 +1,112 @@
use std::cmp;
use primitive::{fast_set, fast_set64, fast_copy64};
static FONT: &'static [u8] = include_bytes!("../../../res/unifont.font");
/// A display
pub struct Display {
pub width: usize,
pub height: usize,
pub onscreen: &'static mut [u32],
pub offscreen: &'static mut [u32],
}
impl Display {
pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display {
Display {
width: width,
height: height,
onscreen: onscreen,
offscreen: offscreen,
}
}
/// Draw a rectangle
pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
let start_y = cmp::min(self.height - 1, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width - 1, x);
let len = cmp::min(self.width, x + w) - start_x;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
onscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
unsafe {
fast_set(offscreen_ptr as *mut u32, color, len);
fast_set(onscreen_ptr as *mut u32, color, len);
}
offscreen_ptr += stride;
onscreen_ptr += stride;
rows -= 1;
}
}
/// Draw a character
fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
if x + 8 <= self.width && y + 16 <= self.height {
let mut font_i = 16 * (character as usize);
let font_end = font_i + 16;
if font_end <= FONT.len() {
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + x * 4;
offscreen_ptr += offset;
onscreen_ptr += offset;
while font_i < font_end {
let mut row_data = FONT[font_i];
let mut col = 8;
while col > 0 {
col -= 1;
if row_data & 1 == 1 {
unsafe {
*((offscreen_ptr + col * 4) as *mut u32) = color;
}
}
row_data = row_data >> 1;
}
unsafe {
fast_copy64(onscreen_ptr as *mut u64, offscreen_ptr as *const u64, 4);
}
offscreen_ptr += stride;
onscreen_ptr += stride;
font_i += 1;
}
}
}
}
/// Scroll display
pub fn scroll(&mut self, rows: usize, color: u32) {
let data = (color as u64) << 32 | color as u64;
let width = self.width/2;
let height = self.height;
if rows > 0 && rows < height {
let off1 = rows * width;
let off2 = height * width - off1;
unsafe {
let data_ptr = self.offscreen.as_mut_ptr() as *mut u64;
fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2);
fast_set64(data_ptr.offset(off2 as isize), data, off1);
fast_copy64(self.onscreen.as_mut_ptr() as *mut u64, data_ptr, off1 + off2);
}
}
}
}

54
drivers/vesad/src/main.rs Normal file
View file

@ -0,0 +1,54 @@
#![feature(alloc)]
#![feature(asm)]
#![feature(heap_api)]
extern crate alloc;
extern crate syscall;
use std::fs::File;
use std::{slice, thread};
use syscall::{physmap, physunmap, MAP_WRITE, MAP_WRITE_COMBINE};
use display::Display;
use mode_info::VBEModeInfo;
use primitive::fast_set64;
pub mod display;
pub mod mode_info;
pub mod primitive;
fn main() {
let width;
let height;
let physbaseptr;
{
let mode_info = unsafe { &*(physmap(0x5200, 4096, 0).expect("vesad: failed to map VBE info") as *const VBEModeInfo) };
width = mode_info.xresolution as usize;
height = mode_info.yresolution as usize;
physbaseptr = mode_info.physbaseptr as usize;
unsafe { let _ = physunmap(mode_info as *const _ as usize); }
}
if physbaseptr > 0 {
let mut socket = File::create(":display").expect("vesad: failed to create display scheme");
thread::spawn(move || {
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") };
unsafe { fast_set64(onscreen as *mut u64, 0, size/2) };
let offscreen = unsafe { alloc::heap::allocate(size * 4, 4096) };
unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
let mut display = 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) }
);
display.rect(100, 100, 100, 100, 0xFF0000);
});
}
}

View file

@ -0,0 +1,37 @@
/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
attributes: u16,
win_a: u8,
win_b: u8,
granularity: u16,
winsize: u16,
segment_a: u16,
segment_b: u16,
winfuncptr: u32,
bytesperscanline: u16,
pub xresolution: u16,
pub yresolution: u16,
xcharsize: u8,
ycharsize: u8,
numberofplanes: u8,
bitsperpixel: u8,
numberofbanks: u8,
memorymodel: u8,
banksize: u8,
numberofimagepages: u8,
unused: u8,
redmasksize: u8,
redfieldposition: u8,
greenmasksize: u8,
greenfieldposition: u8,
bluemasksize: u8,
bluefieldposition: u8,
rsvdmasksize: u8,
rsvdfieldposition: u8,
directcolormodeinfo: u8,
pub physbaseptr: u32,
offscreenmemoryoffset: u32,
offscreenmemsize: u16,
}

View file

@ -0,0 +1,38 @@
#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
asm!("cld
rep movsq"
:
: "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
: "cc", "memory"
: "intel", "volatile");
}
#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
pub unsafe fn fast_set(dst: *mut u32, src: u32, len: usize) {
asm!("cld
rep stosd"
:
: "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len)
: "cc", "memory"
: "intel", "volatile");
}
#[cfg(target_arch = "x86_64")]
#[allow(unused_assignments)]
#[inline(always)]
#[cold]
pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
asm!("cld
rep stosq"
:
: "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
: "cc", "memory"
: "intel", "volatile");
}

5
initfs/etc/init.rc Normal file
View file

@ -0,0 +1,5 @@
initfs:bin/vesad
initfs:bin/ps2d
initfs:bin/pcid
initfs:bin/example
initfs:bin/ion

View file

@ -3,7 +3,8 @@ use collections::VecDeque;
use spin::Mutex;
use arch::externs::memset;
use arch::paging::{ActivePageTable, InactivePageTable, Page, PageIter, VirtualAddress};
use arch::memory::Frame;
use arch::paging::{ActivePageTable, InactivePageTable, Page, PageIter, PhysicalAddress, VirtualAddress};
use arch::paging::entry::{self, EntryFlags};
use arch::paging::temporary_page::TemporaryPage;
@ -55,6 +56,47 @@ impl Grant {
});
}
pub fn physmap(from: PhysicalAddress, to: VirtualAddress, size: usize, flags: EntryFlags) -> Grant {
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
let start_page = Page::containing_address(to);
let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1));
for page in Page::range_inclusive(start_page, end_page) {
let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get() - to.get() + from.get()));
active_table.map_to(page, frame, flags);
flush_all = true;
}
if flush_all {
active_table.flush_all();
}
Grant {
start: to,
size: size,
flags: flags
}
}
pub fn physunmap(self) {
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
let start_page = Page::containing_address(self.start);
let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1));
for page in Page::range_inclusive(start_page, end_page) {
active_table.unmap_return(page);
flush_all = true;
}
if flush_all {
active_table.flush_all();
}
}
pub fn start_address(&self) -> VirtualAddress {
self.start
}

View file

@ -7,6 +7,9 @@ use syscall::error::*;
use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END};
use syscall::scheme::Scheme;
#[path="../../build/userspace/initfs.rs"]
mod gen;
struct Handle {
data: &'static [u8],
seek: usize
@ -20,18 +23,9 @@ pub struct InitFsScheme {
impl InitFsScheme {
pub fn new() -> InitFsScheme {
let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new();
files.insert(b"bin/init", include_bytes!("../../build/userspace/init"));
files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion"));
files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid"));
files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d"));
files.insert(b"bin/example", include_bytes!("../../build/userspace/example"));
files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\ninitfs:bin/example\ninitfs:bin/ion");
InitFsScheme {
next_id: AtomicUsize::new(0),
files: files,
files: gen::gen(),
handles: RwLock::new(BTreeMap::new())
}
}

View file

@ -44,6 +44,8 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
SYS_CLONE => clone(b, stack),
SYS_YIELD => sched_yield(),
SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
SYS_PHYSMAP => physmap(b, c, d),
SYS_PHYSUNMAP => physunmap(b),
_ => {
println!("Unknown syscall {}", a);
Err(Error::new(ENOSYS))

View file

@ -9,14 +9,16 @@ use spin::Mutex;
use arch;
use arch::externs::memcpy;
use arch::memory::allocate_frame;
use arch::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, entry};
use arch::paging::{ActivePageTable, InactivePageTable, Page, PhysicalAddress, VirtualAddress, entry};
use arch::paging::temporary_page::TemporaryPage;
use arch::start::usermode;
use context;
use context::memory::Grant;
use elf::{self, program_header};
use scheme;
use syscall;
use syscall::error::*;
use syscall::flag::{CLONE_VM, CLONE_FS, CLONE_FILES, MAP_WRITE, MAP_WRITE_COMBINE};
use syscall::validate::{validate_slice, validate_slice_mut};
pub fn brk(address: usize) -> Result<usize> {
@ -51,16 +53,7 @@ pub fn brk(address: usize) -> Result<usize> {
}
}
pub const CLONE_VM: usize = 0x100;
pub const CLONE_FS: usize = 0x200;
pub const CLONE_FILES: usize = 0x400;
pub const CLONE_VFORK: usize = 0x4000;
pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
//TODO: Copy on write?
// vfork not supported
assert!(flags & CLONE_VFORK == 0);
let ppid;
let pid;
{
@ -500,6 +493,83 @@ pub fn iopl(_level: usize) -> Result<usize> {
Ok(0)
}
//TODO: verify exlusive access to physical memory
pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
if size == 0 {
Ok(0)
} else {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let mut grants = context.grants.lock();
let from_address = (physical_address/4096) * 4096;
let offset = physical_address - from_address;
let full_size = ((offset + size + 4095)/4096) * 4096;
let mut to_address = arch::USER_GRANT_OFFSET;
let mut entry_flags = entry::PRESENT | entry::NO_EXECUTE | entry::USER_ACCESSIBLE;
if flags & MAP_WRITE == MAP_WRITE {
entry_flags |= entry::WRITABLE;
}
if flags & MAP_WRITE_COMBINE == MAP_WRITE_COMBINE {
entry_flags |= entry::HUGE_PAGE;
}
for i in 0 .. grants.len() {
let start = grants[i].start_address().get();
if to_address + full_size < start {
grants.insert(i, Grant::physmap(
PhysicalAddress::new(from_address),
VirtualAddress::new(to_address),
full_size,
entry_flags
));
return Ok(to_address + offset);
} else {
let pages = (grants[i].size() + 4095) / 4096;
let end = start + pages * 4096;
to_address = end;
}
}
grants.push(Grant::physmap(
PhysicalAddress::new(from_address),
VirtualAddress::new(to_address),
full_size,
entry_flags
));
Ok(to_address + offset)
}
}
pub fn physunmap(virtual_address: usize) -> Result<usize> {
if virtual_address == 0 {
Ok(0)
} else {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let mut grants = context.grants.lock();
for i in 0 .. grants.len() {
let start = grants[i].start_address().get();
let end = start + grants[i].size();
if virtual_address >= start && virtual_address < end {
grants.remove(i).physunmap();
return Ok(0);
}
}
Err(Error::new(EFAULT))
}
}
pub fn sched_yield() -> Result<usize> {
unsafe { context::switch(); }
Ok(0)

View file

@ -14,14 +14,17 @@ pub const CLONE_SUPERVISE: usize = 0x400000;
pub const CLOCK_REALTIME: usize = 1;
pub const CLOCK_MONOTONIC: usize = 4;
pub const MODE_DIR: u16 = 0x4000;
pub const MODE_FILE: u16 = 0x8000;
pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE;
pub const FUTEX_WAIT: usize = 0;
pub const FUTEX_WAKE: usize = 1;
pub const FUTEX_REQUEUE: usize = 2;
pub const MAP_WRITE: usize = 1;
pub const MAP_WRITE_COMBINE: usize = 2;
pub const MODE_DIR: u16 = 0x4000;
pub const MODE_FILE: u16 = 0x8000;
pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE;
pub const SEEK_SET: usize = 0;
pub const SEEK_CUR: usize = 1;
pub const SEEK_END: usize = 2;

View file

@ -110,6 +110,14 @@ pub fn open(path: &str, flags: usize) -> Result<usize> {
unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) }
}
pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
syscall3(SYS_PHYSMAP, physical_address, size, flags)
}
pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> {
syscall1(SYS_PHYSUNMAP, virtual_address)
}
pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> {
unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) }
}

View file

@ -19,6 +19,8 @@ pub const SYS_LSEEK: usize = 19;
pub const SYS_MKDIR: usize = 39;
pub const SYS_NANOSLEEP: usize = 162;
pub const SYS_OPEN: usize = 5;
pub const SYS_PHYSMAP: usize = 945;
pub const SYS_PHYSUNMAP: usize = 946;
pub const SYS_PIPE2: usize = 331;
pub const SYS_READ: usize = 3;
pub const SYS_RMDIR: usize = 84;