diff --git a/.gitignore b/.gitignore index 7bb374e..6738f91 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ Cargo.lock build target +initfs/bin diff --git a/Makefile b/Makefile index 6bd76aa..7658d6a 100644 --- a/Makefile +++ b/Makefile @@ -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 '}' >> $@ diff --git a/arch/x86_64/Cargo.toml b/arch/x86_64/Cargo.toml index 567b412..48e9076 100644 --- a/arch/x86_64/Cargo.toml +++ b/arch/x86_64/Cargo.toml @@ -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] diff --git a/arch/x86_64/src/console.rs b/arch/x86_64/src/console.rs index d19583a..92f28d8 100644 --- a/arch/x86_64/src/console.rs +++ b/arch/x86_64/src/console.rs @@ -1,31 +1,14 @@ use core::fmt::{self, Write}; use spin::Mutex; -use device::display; use device::serial::COM1; -pub static CONSOLE: Mutex = Mutex::new(Console::new()); +pub static CONSOLE: Mutex = 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) } } diff --git a/arch/x86_64/src/device/display.rs b/arch/x86_64/src/device/display.rs deleted file mode 100644 index 6716250..0000000 --- a/arch/x86_64/src/device/display.rs +++ /dev/null @@ -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> = Mutex::new(None); - -pub static DISPLAY: Mutex> = 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); - } - } - } -} diff --git a/arch/x86_64/src/device/mod.rs b/arch/x86_64/src/device/mod.rs index c803264..ff8f7c7 100644 --- a/arch/x86_64/src/device/mod.rs +++ b/arch/x86_64/src/device/mod.rs @@ -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); } diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index 009f722..ff0f9fb 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -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; diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index 10f53c5..a078971 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -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); diff --git a/drivers/vesad/Cargo.toml b/drivers/vesad/Cargo.toml new file mode 100644 index 0000000..eb9335b --- /dev/null +++ b/drivers/vesad/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "vesad" +version = "0.1.0" + +[dependencies] +syscall = { path = "../../syscall/" } diff --git a/drivers/vesad/src/display.rs b/drivers/vesad/src/display.rs new file mode 100644 index 0000000..f1befd3 --- /dev/null +++ b/drivers/vesad/src/display.rs @@ -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); + } + } + } +} diff --git a/drivers/vesad/src/main.rs b/drivers/vesad/src/main.rs new file mode 100644 index 0000000..c85b3df --- /dev/null +++ b/drivers/vesad/src/main.rs @@ -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); + }); + } +} diff --git a/drivers/vesad/src/mode_info.rs b/drivers/vesad/src/mode_info.rs new file mode 100644 index 0000000..7d59af6 --- /dev/null +++ b/drivers/vesad/src/mode_info.rs @@ -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, +} diff --git a/drivers/vesad/src/primitive.rs b/drivers/vesad/src/primitive.rs new file mode 100644 index 0000000..e3bdc25 --- /dev/null +++ b/drivers/vesad/src/primitive.rs @@ -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"); +} diff --git a/initfs/etc/init.rc b/initfs/etc/init.rc new file mode 100644 index 0000000..b24016f --- /dev/null +++ b/initfs/etc/init.rc @@ -0,0 +1,5 @@ +initfs:bin/vesad +initfs:bin/ps2d +initfs:bin/pcid +initfs:bin/example +initfs:bin/ion diff --git a/kernel/context/memory.rs b/kernel/context/memory.rs index 3121794..143ee53 100644 --- a/kernel/context/memory.rs +++ b/kernel/context/memory.rs @@ -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 } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 84df203..525e0a7 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -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()) } } diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index b37a056..5ade167 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -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)) diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 3d94a11..6a91e47 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -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 { @@ -51,16 +53,7 @@ pub fn brk(address: usize) -> Result { } } -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 { - //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 { Ok(0) } +//TODO: verify exlusive access to physical memory +pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result { + 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 { + 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 { unsafe { context::switch(); } Ok(0) diff --git a/syscall/src/flag.rs b/syscall/src/flag.rs index fa00558..5351384 100644 --- a/syscall/src/flag.rs +++ b/syscall/src/flag.rs @@ -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; diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 099f61f..3acc70a 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -110,6 +110,14 @@ pub fn open(path: &str, flags: usize) -> Result { unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) } } +pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result { + syscall3(SYS_PHYSMAP, physical_address, size, flags) +} + +pub unsafe fn physunmap(virtual_address: usize) -> Result { + syscall1(SYS_PHYSUNMAP, virtual_address) +} + pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result { unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) } } diff --git a/syscall/src/number.rs b/syscall/src/number.rs index e65c37f..80e7065 100644 --- a/syscall/src/number.rs +++ b/syscall/src/number.rs @@ -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;