WIP: VESA driver. Make initfs generated by code
This commit is contained in:
parent
a4ede1d23d
commit
e110ab81b8
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
Cargo.lock
|
||||
build
|
||||
target
|
||||
initfs/bin
|
||||
|
|
34
Makefile
34
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 '}' >> $@
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
6
drivers/vesad/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "vesad"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
syscall = { path = "../../syscall/" }
|
112
drivers/vesad/src/display.rs
Normal file
112
drivers/vesad/src/display.rs
Normal 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
54
drivers/vesad/src/main.rs
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
37
drivers/vesad/src/mode_info.rs
Normal file
37
drivers/vesad/src/mode_info.rs
Normal 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,
|
||||
}
|
38
drivers/vesad/src/primitive.rs
Normal file
38
drivers/vesad/src/primitive.rs
Normal 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
5
initfs/etc/init.rc
Normal file
|
@ -0,0 +1,5 @@
|
|||
initfs:bin/vesad
|
||||
initfs:bin/ps2d
|
||||
initfs:bin/pcid
|
||||
initfs:bin/example
|
||||
initfs:bin/ion
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue