diff --git a/os/Cargo.toml b/os/Cargo.toml index 752d71713e818816346af27cc8f79611e71c899d..4ebae8a4591fe6c984ad653679d27fb66c0d8802 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -2,7 +2,7 @@ name = "os" version = "0.1.0" authors = ["Yifan Wu "] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -18,6 +18,9 @@ k210-pac = { git = "https://github.com/wyfcyx/k210-pac" } k210-hal = { git = "https://github.com/wyfcyx/k210-hal" } k210-soc = { git = "https://github.com/wyfcyx/k210-soc" } easy-fs = { path = "../easy-fs" } +virtio-input-decoder = "0.1.4" +embedded-graphics = "0.7.1" +tinybmp = "0.3.1" [features] board_qemu = [] diff --git a/os/Makefile b/os/Makefile index 0601e393216e3d749f395871dd3436a842d4e0ed..b38c23a6773fbfe89554b61f09cad7404d163149 100644 --- a/os/Makefile +++ b/os/Makefile @@ -89,15 +89,35 @@ disasm-vim: kernel run: run-inner +gui: build +ifeq ($(BOARD),qemu) + @qemu-system-riscv64 \ + -M 128m \ + -machine virt \ + -bios $(BOOTLOADER) \ + -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \ + -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0 \ + -device virtio-gpu-device \ + -device virtio-keyboard-device \ + -device virtio-mouse-device \ + -serial stdio +endif + run-inner: build ifeq ($(BOARD),qemu) @qemu-system-riscv64 \ + -M 128m \ -machine virt \ - -nographic \ -bios $(BOOTLOADER) \ + -display none \ -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \ -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ - -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 + -device virtio-blk-device,drive=x0 \ + -device virtio-gpu-device \ + -device virtio-keyboard-device \ + -device virtio-mouse-device \ + -serial stdio else (which $(K210-BURNER)) || (cd .. && git clone https://github.com/sipeed/kflash.py.git && mv kflash.py tools) @cp $(BOOTLOADER) $(BOOTLOADER).copy diff --git a/os/run-fdt.sh b/os/run-fdt.sh new file mode 100755 index 0000000000000000000000000000000000000000..c7c886d1431d343341bad97461bce211429e9d69 --- /dev/null +++ b/os/run-fdt.sh @@ -0,0 +1,11 @@ +qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out \ +-bios ../bootloader/rustsbi-qemu.bin \ +-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \ +-drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \ +-device virtio-blk-device,drive=x0 \ +-device virtio-gpu-device \ +-device virtio-keyboard-device \ +-device virtio-mouse-device \ +-serial stdio + +fdtdump virt.out \ No newline at end of file diff --git a/os/run-nodisp.sh b/os/run-nodisp.sh new file mode 100755 index 0000000000000000000000000000000000000000..7f2a5bb4b9b31d1d1b850320ace934d66c5c8f1a --- /dev/null +++ b/os/run-nodisp.sh @@ -0,0 +1,10 @@ +qemu-system-riscv64 -M 128m -machine virt \ +-bios ../bootloader/rustsbi-qemu.bin \ +-display none \ +-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \ +-drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \ +-device virtio-blk-device,drive=x0 \ +-device virtio-gpu-device \ +-device virtio-keyboard-device \ +-device virtio-mouse-device \ +-serial stdio diff --git a/os/run.sh b/os/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..f9e96d6cf2927d3cc6e77580b33aead31bf880b9 --- /dev/null +++ b/os/run.sh @@ -0,0 +1,9 @@ +qemu-system-riscv64 -M 128m -machine virt \ +-bios ../bootloader/rustsbi-qemu.bin \ +-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \ +-drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \ +-device virtio-blk-device,drive=x0 \ +-device virtio-gpu-device \ +-device virtio-keyboard-device \ +-device virtio-mouse-device \ +-serial stdio diff --git a/os/src/assert/desktop.bmp b/os/src/assert/desktop.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a754f7a7e2fa0b5012e83216eb644c2b82c3fb54 Binary files /dev/null and b/os/src/assert/desktop.bmp differ diff --git a/os/src/assert/file.bmp b/os/src/assert/file.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4a4e83bb62e2171a3484c9ae26bd65242e2a7661 Binary files /dev/null and b/os/src/assert/file.bmp differ diff --git a/os/src/assert/folder.bmp b/os/src/assert/folder.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c8384cb722b02b7c1b0980440e6b2d5ca427d15a Binary files /dev/null and b/os/src/assert/folder.bmp differ diff --git a/os/src/assert/mouse.bmp b/os/src/assert/mouse.bmp new file mode 100644 index 0000000000000000000000000000000000000000..22a4613c2b04d275fa7f82c671f52eb03ac26eff Binary files /dev/null and b/os/src/assert/mouse.bmp differ diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index 19ec397c87b8799410bd576fe246e887bfdda0f5..1dae9f3dcebe1e5b57cb65d0c5552fcfa10a3aa4 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -1,10 +1,10 @@ pub const CLOCK_FREQ: usize = 12500000; pub const MMIO: &[(usize, usize)] = &[ - (0x1000_0000, 0x1000), // VIRT_UART0 in virt machine - (0x1000_1000, 0x1000), // VIRT_VIRTIO in virt machine - (0x0C00_0000, 0x40_0000), // VIRT_PLIC in virt machine (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine + (0x2000000, 0x10000), + (0xc000000, 0x210000), // VIRT_PLIC in virt machine + (0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine ]; pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock; @@ -13,9 +13,13 @@ pub type CharDeviceImpl = crate::drivers::chardev::NS16550a; pub const VIRT_PLIC: usize = 0xC00_0000; pub const VIRT_UART: usize = 0x1000_0000; +pub const VIRTGPU_XRES: u32 = 1280; +pub const VIRTGPU_YRES: u32 = 800; + use crate::drivers::block::BLOCK_DEVICE; use crate::drivers::chardev::{CharDevice, UART}; use crate::drivers::plic::{IntrTargetPriority, PLIC}; +use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE}; pub fn device_init() { use riscv::register::sie; @@ -25,7 +29,8 @@ pub fn device_init() { let machine = IntrTargetPriority::Machine; plic.set_threshold(hart_id, supervisor, 0); plic.set_threshold(hart_id, machine, 1); - for intr_src_id in [1usize, 10] { + //irq nums: 5 keyboard, 6 mouse, 8 block, 10 uart + for intr_src_id in [5usize, 6, 8 , 10] { plic.enable(hart_id, supervisor, intr_src_id); plic.set_priority(intr_src_id, 1); } @@ -38,7 +43,9 @@ pub fn irq_handler() { let mut plic = unsafe { PLIC::new(VIRT_PLIC) }; let intr_src_id = plic.claim(0, IntrTargetPriority::Supervisor); match intr_src_id { - 1 => BLOCK_DEVICE.handle_irq(), + 5 => KEYBOARD_DEVICE.handle_irq(), + 6 => MOUSE_DEVICE.handle_irq(), + 8 => BLOCK_DEVICE.handle_irq(), 10 => UART.handle_irq(), _ => panic!("unsupported IRQ {}", intr_src_id), } diff --git a/os/src/config.rs b/os/src/config.rs index 41fe977c2a65ccab4494cfe30bde5beb6a226be6..8f8b709a36d4ee4481f4be7ce54035551ac43aaa 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -2,8 +2,8 @@ pub const USER_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_STACK_SIZE: usize = 4096 * 2; -pub const KERNEL_HEAP_SIZE: usize = 0x20_0000; -pub const MEMORY_END: usize = 0x80800000; +pub const KERNEL_HEAP_SIZE: usize = 0x100_0000; +pub const MEMORY_END: usize = 0x88000000; pub const PAGE_SIZE: usize = 0x1000; pub const PAGE_SIZE_BITS: usize = 0xc; diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs index 75e69c175a4977c4a92002bfdda05e489c9584b4..ff460d7592aac9c49c80c466d2d4c2f1ac5c198f 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -12,7 +12,7 @@ use lazy_static::*; use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader}; #[allow(unused)] -const VIRTIO0: usize = 0x10001000; +const VIRTIO0: usize = 0x10008000; pub struct VirtIOBlock { virtio_blk: UPIntrFreeCell>, diff --git a/os/src/drivers/gpu/mod.rs b/os/src/drivers/gpu/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..2dc80d48b4d7fd68558793b16591f6d118b62ee1 --- /dev/null +++ b/os/src/drivers/gpu/mod.rs @@ -0,0 +1,66 @@ +use crate::sync::UPIntrFreeCell; +use alloc::{sync::Arc, vec::Vec}; +use core::any::Any; +use embedded_graphics::pixelcolor::Rgb888; +use tinybmp::Bmp; +use virtio_drivers::{VirtIOGpu, VirtIOHeader}; +const VIRTIO7: usize = 0x10007000; +pub trait GPUDevice: Send + Sync + Any { + fn update_cursor(&self); + fn getfreambuffer(&self) -> &mut [u8]; + fn flush(&self); +} + +lazy_static::lazy_static!( + pub static ref GPU_DEVICE: Arc = Arc::new(VirtIOGPU::new()); +); + +pub struct VirtIOGPU { + gpu: UPIntrFreeCell>, + fb: &'static [u8], +} +static BMP_DATA: &[u8] = include_bytes!("../../assert/mouse.bmp"); +impl VirtIOGPU { + pub fn new() -> Self { + unsafe { + let mut virtio = VirtIOGpu::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap(); + + let fbuffer = virtio.setup_framebuffer().unwrap(); + let len = fbuffer.len(); + let ptr = fbuffer.as_mut_ptr(); + let fb = core::slice::from_raw_parts_mut(ptr, len); + + let bmp = Bmp::::from_slice(BMP_DATA).unwrap(); + let raw = bmp.as_raw(); + let mut b = Vec::new(); + for i in raw.image_data().chunks(3) { + let mut v = i.to_vec(); + b.append(&mut v); + if i == [255, 255, 255] { + b.push(0x0) + } else { + b.push(0xff) + } + } + virtio.setup_cursor(b.as_slice(), 50, 50, 50, 50).unwrap(); + + Self { + gpu: UPIntrFreeCell::new(virtio), + fb, + } + } + } +} + +impl GPUDevice for VirtIOGPU { + fn flush(&self) { + self.gpu.exclusive_access().flush().unwrap(); + } + fn getfreambuffer(&self) -> &mut [u8] { + unsafe { + let ptr = self.fb.as_ptr() as *const _ as *mut u8; + core::slice::from_raw_parts_mut(ptr, self.fb.len()) + } + } + fn update_cursor(&self) {} +} diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..0acb03455ec0863d1a78dbc3917acb5056622536 --- /dev/null +++ b/os/src/drivers/input/mod.rs @@ -0,0 +1,74 @@ +use crate::{ + gui::{Button, Component}, + sync::UPIntrFreeCell, + syscall::PAD, +}; +use alloc::{string::ToString, sync::Arc}; +use core::any::Any; +use embedded_graphics::{ + prelude::{Point, Size}, + text::Text, +}; +use k210_hal::cache::Uncache; +use virtio_drivers::{VirtIOHeader, VirtIOInput}; +use virtio_input_decoder::{Decoder, Key, KeyType}; + +use super::GPU_DEVICE; + +const VIRTIO5: usize = 0x10005000; +const VIRTIO6: usize = 0x10006000; + +struct VirtIOINPUT(UPIntrFreeCell>); + +pub trait INPUTDevice: Send + Sync + Any { + fn handle_irq(&self); +} + +lazy_static::lazy_static!( + pub static ref KEYBOARD_DEVICE: Arc = Arc::new(VirtIOINPUT::new(VIRTIO5)); + pub static ref MOUSE_DEVICE: Arc = Arc::new(VirtIOINPUT::new(VIRTIO6)); +); + +impl VirtIOINPUT { + pub fn new(addr: usize) -> Self { + Self(unsafe { + UPIntrFreeCell::new(VirtIOInput::new(&mut *(addr as *mut VirtIOHeader)).unwrap()) + }) + } +} + +impl INPUTDevice for VirtIOINPUT { + fn handle_irq(&self) { + let mut input = self.0.exclusive_access(); + input.ack_interrupt(); + let event = input.pop_pending_event().unwrap(); + let dtype = match Decoder::decode( + event.event_type as usize, + event.code as usize, + event.value as usize, + ) { + Ok(dtype) => dtype, + Err(_) => return, + }; + match dtype { + virtio_input_decoder::DecodeType::Key(key, r#type) => { + println!("{:?} {:?}", key, r#type); + if r#type == KeyType::Press { + let mut inner = PAD.exclusive_access(); + let a = inner.as_ref().unwrap(); + match key.to_char() { + Ok(mut k) => { + if k == '\r' { + a.repaint(k.to_string() + "\n") + } else { + a.repaint(k.to_string()) + } + } + Err(_) => {} + } + } + } + virtio_input_decoder::DecodeType::Mouse(mouse) => println!("{:?}", mouse), + } + } +} diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index c1b1231f5d51f587d43a7f79e9f9f9e44539161c..337c76d9e87e5ce729c9107edb6da7e8d2d0c686 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,6 +1,9 @@ pub mod block; pub mod chardev; +pub mod gpu; +pub mod input; pub mod plic; - pub use block::BLOCK_DEVICE; pub use chardev::UART; +pub use gpu::*; +pub use input::*; diff --git a/os/src/fs/mod.rs b/os/src/fs/mod.rs index 8ae0418c5ce76d0b41a933fdd4c485451d59d0e1..221d68b32f7d3e724f8f7a97ab0c712ae7e336b6 100644 --- a/os/src/fs/mod.rs +++ b/os/src/fs/mod.rs @@ -11,6 +11,6 @@ pub trait File: Send + Sync { fn write(&self, buf: UserBuffer) -> usize; } -pub use inode::{list_apps, open_file, OSInode, OpenFlags}; +pub use inode::{list_apps, open_file, OSInode, OpenFlags, ROOT_INODE}; pub use pipe::{make_pipe, Pipe}; pub use stdio::{Stdin, Stdout}; diff --git a/os/src/gui/button.rs b/os/src/gui/button.rs new file mode 100644 index 0000000000000000000000000000000000000000..dee2f7c262b76a7434ef307c274cf99e6d06811b --- /dev/null +++ b/os/src/gui/button.rs @@ -0,0 +1,79 @@ +use alloc::{string::String, sync::Arc}; +use embedded_graphics::{ + mono_font::{ + ascii::{FONT_10X20, FONT_6X10}, + MonoTextStyle, + }, + pixelcolor::Rgb888, + prelude::{Dimensions, Point, Primitive, RgbColor, Size}, + primitives::{PrimitiveStyle, Rectangle}, + text::{Alignment, Text}, + Drawable, +}; + +use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; + +use super::{Component, Graphics}; + +pub struct Button { + inner: UPIntrFreeCell, +} + +pub struct ButtonInner { + graphic: Graphics, + text: String, + parent: Option>, +} + +impl Button { + pub fn new(size: Size, point: Point, parent: Option>, text: String) -> Self { + let point = match &parent { + Some(p) => { + let (_, p) = p.bound(); + Point::new(p.x + point.x, p.y + point.y) + } + None => point, + }; + Self { + inner: unsafe { + UPIntrFreeCell::new(ButtonInner { + graphic: Graphics { + size, + point, + drv: GPU_DEVICE.clone(), + }, + text, + parent, + }) + }, + } + } +} + +impl Component for Button { + fn paint(&self) { + let mut inner = self.inner.exclusive_access(); + let text = inner.text.clone(); + Text::with_alignment( + text.as_str(), + inner.graphic.bounding_box().center(), + MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), + Alignment::Center, + ) + .draw(&mut inner.graphic); + } + + fn add(&self, comp: alloc::sync::Arc) { + unreachable!() + } + + fn bound( + &self, + ) -> ( + embedded_graphics::prelude::Size, + embedded_graphics::prelude::Point, + ) { + let inner = self.inner.exclusive_access(); + (inner.graphic.size, inner.graphic.point) + } +} diff --git a/os/src/gui/graphic.rs b/os/src/gui/graphic.rs new file mode 100644 index 0000000000000000000000000000000000000000..cda752065d10ca4b64da0f9d8a8144e95261abe8 --- /dev/null +++ b/os/src/gui/graphic.rs @@ -0,0 +1,57 @@ +use alloc::sync::Arc; +use embedded_graphics::{ + draw_target::DrawTarget, + pixelcolor::Rgb888, + prelude::{OriginDimensions, Point, RgbColor, Size}, +}; + +use crate::drivers::{GPUDevice, GPU_DEVICE,}; +use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES}; + +#[derive(Clone)] +pub struct Graphics { + pub size: Size, + pub point: Point, + pub drv: Arc, +} + +impl Graphics { + pub fn new(size: Size, point: Point) -> Self { + Self { + size, + point, + drv: GPU_DEVICE.clone(), + } + } +} + +impl OriginDimensions for Graphics { + fn size(&self) -> Size { + self.size + } +} + +impl DrawTarget for Graphics { + type Color = Rgb888; + + type Error = core::convert::Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + let fb = self.drv.getfreambuffer(); + + pixels.into_iter().for_each(|px| { + let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) as usize * 4; + if idx + 2 >= fb.len() { + return; + } + fb[idx] = px.1.b(); + fb[idx + 1] = px.1.g(); + fb[idx + 2] = px.1.r(); + }); + self.drv.flush(); + Ok(()) + } +} diff --git a/os/src/gui/icon.rs b/os/src/gui/icon.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d78470929dfab536797c91dddc903e55c3afa49 --- /dev/null +++ b/os/src/gui/icon.rs @@ -0,0 +1,79 @@ +use alloc::{string::String, sync::Arc, vec::Vec}; +use embedded_graphics::{ + image::Image, + mono_font::{ascii::FONT_10X20, iso_8859_13::FONT_6X12, MonoTextStyle}, + pixelcolor::Rgb888, + prelude::{Point, RgbColor, Size}, + text::Text, + Drawable, +}; +use tinybmp::Bmp; + +use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; +use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES}; +use super::{Component, Graphics, ImageComp}; + +static FILEICON: &[u8] = include_bytes!("../assert/file.bmp"); + +pub struct IconController { + inner: UPIntrFreeCell, +} + +pub struct IconControllerInner { + files: Vec, + graphic: Graphics, + parent: Option>, +} + +impl IconController { + pub fn new(files: Vec, parent: Option>) -> Self { + IconController { + inner: unsafe { + UPIntrFreeCell::new(IconControllerInner { + files, + graphic: Graphics { + size: Size::new(VIRTGPU_XRES, VIRTGPU_YRES), + point: Point::new(0, 0), + drv: GPU_DEVICE.clone(), + }, + parent, + }) + }, + } + } +} + +impl Component for IconController { + fn paint(&self) { + println!("demo"); + let mut inner = self.inner.exclusive_access(); + let mut x = 10; + let mut y = 10; + let v = inner.files.clone(); + for file in v { + println!("file"); + let bmp = Bmp::::from_slice(FILEICON).unwrap(); + Image::new(&bmp, Point::new(x, y)).draw(&mut inner.graphic); + let text = Text::new( + file.as_str(), + Point::new(x + 20, y + 80), + MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), + ); + text.draw(&mut inner.graphic); + if y >= 600 { + x = x + 70; + y = 10; + } else { + y = y + 90; + } + } + } + + fn add(&self, comp: Arc) { + todo!() + } + + fn bound(&self) -> (Size, Point) { + todo!() + } +} diff --git a/os/src/gui/image.rs b/os/src/gui/image.rs new file mode 100644 index 0000000000000000000000000000000000000000..aac5829a512aa9c27b7040212e9a97fb589fb69b --- /dev/null +++ b/os/src/gui/image.rs @@ -0,0 +1,80 @@ +use alloc::{sync::Arc, vec::Vec}; +use embedded_graphics::{ + image::Image, + pixelcolor::Rgb888, + prelude::{Point, Size}, + Drawable, +}; +use tinybmp::Bmp; + +use crate::{ + drivers::{BLOCK_DEVICE, GPU_DEVICE}, + sync::UPIntrFreeCell, +}; + +use super::{Component, Graphics}; + +pub struct ImageComp { + inner: UPIntrFreeCell, +} + +pub struct ImageInner { + image: &'static [u8], + graphic: Graphics, + parent: Option>, +} + +impl ImageComp { + pub fn new( + size: Size, + point: Point, + v: &'static [u8], + parent: Option>, + ) -> Self { + unsafe { + ImageComp { + inner: UPIntrFreeCell::new(ImageInner { + parent, + image: v, + graphic: Graphics { + size, + point, + drv: GPU_DEVICE.clone(), + }, + }), + } + } + } +} + +impl Component for ImageComp { + fn paint(&self) { + let mut inner = self.inner.exclusive_access(); + let b = unsafe { + let len = inner.image.len(); + let ptr = inner.image.as_ptr() as *const u8; + core::slice::from_raw_parts(ptr, len) + }; + let bmp = Bmp::::from_slice(b).unwrap(); + let point = match &inner.parent { + Some(parent) => { + let (_, point) = parent.bound(); + Point::new( + point.x + inner.graphic.point.x, + point.y + inner.graphic.point.y, + ) + } + None => inner.graphic.point, + }; + Image::new(&bmp, point).draw(&mut inner.graphic); + } + + fn add(&self, comp: alloc::sync::Arc) { + todo!() + } + + fn bound(&self) -> (Size, Point) { + let inner = self.inner.exclusive_access(); + (inner.graphic.size, inner.graphic.point) + } +} diff --git a/os/src/gui/mod.rs b/os/src/gui/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..da3aae9b2ebd8fbc5a19c526c34018ae1fedc1ec --- /dev/null +++ b/os/src/gui/mod.rs @@ -0,0 +1,21 @@ +mod button; +mod graphic; +mod icon; +mod image; +mod panel; +mod terminal; +use alloc::sync::Arc; +pub use button::*; +use core::any::Any; +use embedded_graphics::prelude::{Point, Size}; +pub use graphic::*; +pub use icon::*; +pub use image::*; +pub use panel::*; +pub use terminal::*; + +pub trait Component: Send + Sync + Any { + fn paint(&self); + fn add(&self, comp: Arc); + fn bound(&self) -> (Size, Point); +} diff --git a/os/src/gui/panel.rs b/os/src/gui/panel.rs new file mode 100644 index 0000000000000000000000000000000000000000..2af2961aa49c3718501fe6fbbc0cdcc30e0cddbc --- /dev/null +++ b/os/src/gui/panel.rs @@ -0,0 +1,66 @@ +use alloc::{collections::VecDeque, rc::Weak, sync::Arc}; +use embedded_graphics::{ + pixelcolor::Rgb888, + prelude::{Point, Primitive, RgbColor, Size}, + primitives::{PrimitiveStyle, Rectangle}, + Drawable, +}; + +use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; + +use super::{Component, Graphics}; + +pub struct Panel { + inner: UPIntrFreeCell, +} +struct PanelInner { + graphic: Graphics, + comps: VecDeque>, +} + +impl Panel { + pub fn new(size: Size, point: Point) -> Self { + Self { + inner: unsafe { + UPIntrFreeCell::new(PanelInner { + graphic: Graphics { + size, + point, + drv: GPU_DEVICE.clone(), + }, + comps: VecDeque::new(), + }) + }, + } + } +} + +impl Component for Panel { + fn paint(&self) { + let mut inner = self.inner.exclusive_access(); + + Rectangle::new(Point::new(0, 0), inner.graphic.size) + .into_styled(PrimitiveStyle::with_fill(Rgb888::WHITE)) + .draw(&mut inner.graphic) + .unwrap(); + + let len = inner.comps.len(); + drop(inner); + for i in 0..len { + let mut inner = self.inner.exclusive_access(); + let comp = Arc::downgrade(&inner.comps[i]); + drop(inner); + comp.upgrade().unwrap().paint(); + } + } + + fn add(&self, comp: alloc::sync::Arc) { + let mut inner = self.inner.exclusive_access(); + inner.comps.push_back(comp); + } + + fn bound(&self) -> (Size, Point) { + let inner = self.inner.exclusive_access(); + (inner.graphic.size, inner.graphic.point) + } +} diff --git a/os/src/gui/terminal.rs b/os/src/gui/terminal.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d233f568efd51cbadc1bcafc4bb6597a8c792e7 --- /dev/null +++ b/os/src/gui/terminal.rs @@ -0,0 +1,105 @@ +use alloc::{ + collections::VecDeque, + string::{String, ToString}, + sync::Arc, +}; +use embedded_graphics::{ + mono_font::{ascii::FONT_10X20, MonoTextStyle}, + pixelcolor::Rgb888, + prelude::{Dimensions, Point, Primitive, RgbColor, Size}, + primitives::{PrimitiveStyle, Rectangle}, + text::{Alignment, Text}, + Drawable, +}; + +use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; + +use super::{button::Button, Component, Graphics, Panel}; + +pub struct Terminal { + inner: UPIntrFreeCell, +} + +pub struct TerminalInner { + pub text: String, + titel: Option, + graphic: Graphics, + comps: VecDeque>, +} + +impl Terminal { + pub fn new( + size: Size, + point: Point, + parent: Option>, + titel: Option, + text: String, + ) -> Self { + Self { + inner: unsafe { + UPIntrFreeCell::new(TerminalInner { + text, + titel, + graphic: Graphics { + size, + point, + drv: GPU_DEVICE.clone(), + }, + comps: VecDeque::new(), + }) + }, + } + } + + pub fn repaint(&self, text: String) { + let mut inner = self.inner.exclusive_access(); + inner.text += text.as_str(); + Text::with_alignment( + inner.text.clone().as_str(), + Point::new(20, 50), + MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), + Alignment::Left, + ) + .draw(&mut inner.graphic); + } +} + +impl Component for Terminal { + fn paint(&self) { + let mut inner = self.inner.exclusive_access(); + let len = inner.comps.len(); + drop(inner); + for i in 0..len { + let mut inner = self.inner.exclusive_access(); + let comp = Arc::downgrade(&inner.comps[i]); + drop(inner); + comp.upgrade().unwrap().paint(); + } + let mut inner = self.inner.exclusive_access(); + let titel = inner.titel.get_or_insert("No Titel".to_string()).clone(); + let text = Text::new( + titel.as_str(), + Point::new(20, 20), + MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), + ); + text.draw(&mut inner.graphic); + + Text::with_alignment( + inner.text.clone().as_str(), + Point::new(20, 50), + MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), + Alignment::Left, + ) + .draw(&mut inner.graphic); + } + + fn add(&self, comp: Arc) { + let mut inner = self.inner.exclusive_access(); + inner.comps.push_back(comp); + } + + fn bound(&self) -> (Size, Point) { + let inner = self.inner.exclusive_access(); + (inner.graphic.size, inner.graphic.point) + } +} diff --git a/os/src/main.rs b/os/src/main.rs index 3c23069b778b68fde6623568a116ad14094a8815..3b84c24d41db181fb6c5260ab79b3641fa22e01c 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -3,6 +3,8 @@ #![feature(panic_info_message)] #![feature(alloc_error_handler)] +use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; + extern crate alloc; #[macro_use] @@ -20,6 +22,7 @@ mod console; mod config; mod drivers; mod fs; +mod gui; mod lang_items; mod mm; mod sbi; @@ -29,6 +32,8 @@ mod task; mod timer; mod trap; +// use syscall::create_desktop; //for test + core::arch::global_asm!(include_str!("entry.asm")); fn clear_bss() { @@ -54,11 +59,19 @@ lazy_static! { pub fn rust_main() -> ! { clear_bss(); mm::init(); + println!("KERN: init gpu"); + GPU_DEVICE.clone(); + println!("KERN: init keyboard"); + KEYBOARD_DEVICE.clone(); + println!("KERN: init mouse"); + MOUSE_DEVICE.clone(); + println!("KERN: init trap"); trap::init(); trap::enable_timer_interrupt(); timer::set_next_trigger(); board::device_init(); fs::list_apps(); + //syscall::create_desktop(); //for test task::add_initproc(); *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); diff --git a/os/src/syscall/gui.rs b/os/src/syscall/gui.rs new file mode 100644 index 0000000000000000000000000000000000000000..82c42af42487c937997ff264cc731adfbcd3ac67 --- /dev/null +++ b/os/src/syscall/gui.rs @@ -0,0 +1,63 @@ +use alloc::{string::ToString, sync::Arc, vec::Vec}; +use embedded_graphics::{ + prelude::{Point, Size}, + primitives::arc, +}; + +use crate::{ + fs::ROOT_INODE, + gui::{Button, Component, IconController, ImageComp, Panel, Terminal}, + sync::UPIntrFreeCell, +}; + +use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES}; + +static DT: &[u8] = include_bytes!("../assert/desktop.bmp"); + +lazy_static::lazy_static!( + pub static ref DESKTOP:UPIntrFreeCell> = unsafe { + UPIntrFreeCell::new(Arc::new(Panel::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0)))) + }; + pub static ref PAD:UPIntrFreeCell>> = unsafe { + UPIntrFreeCell::new(None) + }; +); + +pub fn create_desktop() -> isize { + let mut p: Arc = + Arc::new(Panel::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0))); + let image = ImageComp::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0), DT, Some(p.clone())); + let icon = IconController::new(ROOT_INODE.ls(), Some(p.clone())); + p.add(Arc::new(image)); + p.add(Arc::new(icon)); + let mut desktop = DESKTOP.exclusive_access(); + *desktop = p; + desktop.paint(); + drop(desktop); + create_terminal(); + 1 +} + +pub fn create_terminal() { + let desktop = DESKTOP.exclusive_access(); + let arc_t = Arc::new(Terminal::new( + Size::new(400, 400), + Point::new(200, 100), + Some(desktop.clone()), + Some("demo.txt".to_string()), + "".to_string(), + )); + let text = Panel::new(Size::new(400, 400), Point::new(200, 100)); + let button = Button::new( + Size::new(20, 20), + Point::new(370, 10), + Some(arc_t.clone()), + "X".to_string(), + ); + arc_t.add(Arc::new(text)); + arc_t.add(Arc::new(button)); + arc_t.paint(); + desktop.add(arc_t.clone()); + let mut pad = PAD.exclusive_access(); + *pad = Some(arc_t); +} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index fa4a4cf1385a91dc12967edfc08f941f85233f17..5d8660f93ce6407a2b7f7a6fb7a4bf32a46aa6a7 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -25,13 +25,16 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022; const SYSCALL_CONDVAR_CREATE: usize = 1030; const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; - +const SYSCALL_CREATE_DESKTOP: usize = 2000; mod fs; +mod gui; mod process; mod sync; mod thread; +pub use self::gui::create_desktop; use fs::*; +pub use gui::PAD; use process::*; use sync::*; use thread::*; @@ -65,6 +68,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), + SYSCALL_CREATE_DESKTOP => create_desktop(), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/user/src/bin/gui.rs b/user/src/bin/gui.rs new file mode 100644 index 0000000000000000000000000000000000000000..e3f7ec2c8bcc7e189b05ae2b790bde3a0f1b152d --- /dev/null +++ b/user/src/bin/gui.rs @@ -0,0 +1,19 @@ +#![no_std] +#![no_main] + +use user_lib::create_desktop; + +#[macro_use] +extern crate user_lib; + + + +#[no_mangle] +pub fn main() -> i32 { + println!("gui"); + create_desktop(); + println!("exit pass."); + loop{} + 0 +} + diff --git a/user/src/lib.rs b/user/src/lib.rs index 729eaef3111b7c259455a3e169ce4d19ce0aa4be..6f57edd4d2b4310899dc65c8565e1ac5057b2bab 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -198,7 +198,9 @@ pub fn condvar_signal(condvar_id: usize) { pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { sys_condvar_wait(condvar_id, mutex_id); } - +pub fn create_desktop() { + sys_create_desktop(); +} #[macro_export] macro_rules! vstore { ($var_ref: expr, $value: expr) => { diff --git a/user/src/syscall.rs b/user/src/syscall.rs index b4bb67a02c5cc76b5346bafd74e17b82e5f30f29..3f36f5337c981d747d033247b07610a969d78d63 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -154,3 +154,6 @@ pub fn sys_condvar_signal(condvar_id: usize) -> isize { pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0]) } +pub fn sys_create_desktop() -> isize { + syscall(2000, [0, 0, 0]) +} \ No newline at end of file