WIP: VESA driver. Make initfs generated by code
This commit is contained in:
		
							parent
							
								
									a4ede1d23d
								
							
						
					
					
						commit
						e110ab81b8
					
				
					 21 changed files with 430 additions and 306 deletions
				
			
		
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Soller
						Jeremy Soller