emerald_std/
graphics.rs

1use core::mem::MaybeUninit;
2
3pub use kernel_user_link::graphics::{FrameBufferInfo, GraphicsCommand};
4use kernel_user_link::{
5    call_syscall,
6    syscalls::{SyscallError, SYS_GRAPHICS},
7};
8
9pub struct BlitCommand<'a> {
10    pub memory: &'a [u8],
11    pub src_framebuffer_info: FrameBufferInfo,
12    pub src: (usize, usize),
13    pub dst: (usize, usize),
14    pub size: (usize, usize),
15}
16
17impl BlitCommand<'_> {
18    fn is_buffer_valid(&self) -> bool {
19        // check the memory buffer
20        let buf_expected_len = self.src_framebuffer_info.memory_size();
21        if self.memory.len() != buf_expected_len {
22            return false;
23        }
24
25        // check the `src`
26        if self.src.0 >= self.src_framebuffer_info.width
27            || self.src.1 >= self.src_framebuffer_info.height
28            || self.src.0 + self.size.0 > self.src_framebuffer_info.width
29            || self.src.1 + self.size.1 > self.src_framebuffer_info.height
30        {
31            return false;
32        }
33
34        // the `dst` relies on the framebuffer info of the kernel
35        // we don't have that info here, so we can't check it
36        true
37    }
38}
39
40/// # Safety
41/// This function assumes that `command` and `extra` are valid.
42/// based on what's expected by the kernel.
43unsafe fn graphics(command: GraphicsCommand, extra: u64) -> Result<(), SyscallError> {
44    unsafe {
45        call_syscall!(
46            SYS_GRAPHICS,
47            command as u64, // command
48            extra,          // extra
49        )
50        .map(|e| assert!(e == 0))
51    }
52}
53
54pub fn take_ownership() -> Result<(), SyscallError> {
55    // Safety: `TakeOwnership` is a valid command, and doesn't require any extra data.
56    unsafe { graphics(GraphicsCommand::TakeOwnership, 0) }
57}
58
59pub fn release_ownership() -> Result<(), SyscallError> {
60    // Safety: `ReleaseOwnership` is a valid command, and doesn't require any extra data.
61    unsafe { graphics(GraphicsCommand::ReleaseOwnership, 0) }
62}
63
64pub fn get_framebuffer_info() -> Result<FrameBufferInfo, SyscallError> {
65    let mut info = MaybeUninit::<FrameBufferInfo>::uninit();
66
67    // Safety: `GetFrameBufferInfo` is a valid command, and requires a valid `FrameBufferInfo` pointer.
68    //         which rust guarantees here.
69    unsafe {
70        graphics(
71            GraphicsCommand::GetFrameBufferInfo,
72            info.as_mut_ptr() as *const _ as u64,
73        )?;
74    }
75
76    // Safety: `info` is now initialized.
77    unsafe { Ok(info.assume_init()) }
78}
79
80pub fn blit(command: &BlitCommand<'_>) -> Result<(), SyscallError> {
81    if !command.is_buffer_valid() {
82        return Err(SyscallError::InvalidGraphicsBuffer);
83    }
84
85    let converted_command = kernel_user_link::graphics::BlitCommand {
86        memory: command.memory.as_ptr(),
87        src_framebuffer_info: command.src_framebuffer_info,
88        src: command.src,
89        dst: command.dst,
90        size: command.size,
91    };
92
93    // Safety: `Blit` is a valid command, and requires a valid `BlitCommand` pointer.
94    //         we just created one right now, so its valid.
95    unsafe { graphics(GraphicsCommand::Blit, &converted_command as *const _ as u64) }
96}