|
| 1 | +use crate::io; |
| 2 | +use crate::iter::Iterator; |
| 3 | +use crate::mem::MaybeUninit; |
| 4 | +use crate::os::uefi; |
| 5 | +use crate::ptr::NonNull; |
| 6 | + |
| 7 | +const MAX_BUFFER_SIZE: usize = 8192; |
| 8 | + |
| 9 | +pub struct Stdin; |
| 10 | +pub struct Stdout; |
| 11 | +pub struct Stderr; |
| 12 | + |
| 13 | +impl Stdin { |
| 14 | + pub const fn new() -> Stdin { |
| 15 | + Stdin |
| 16 | + } |
| 17 | +} |
| 18 | + |
| 19 | +impl io::Read for Stdin { |
| 20 | + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| 21 | + let st: NonNull<r_efi::efi::SystemTable> = uefi::env::system_table().cast(); |
| 22 | + let stdin = unsafe { (*st.as_ptr()).con_in }; |
| 23 | + |
| 24 | + // Try reading any pending data |
| 25 | + let inp = match read_key_stroke(stdin) { |
| 26 | + Ok(x) => x, |
| 27 | + Err(e) if e == r_efi::efi::Status::NOT_READY => { |
| 28 | + // Wait for keypress for new data |
| 29 | + wait_stdin(stdin)?; |
| 30 | + read_key_stroke(stdin).map_err(|x| io::Error::from_raw_os_error(x.as_usize()))? |
| 31 | + } |
| 32 | + Err(e) => { |
| 33 | + return Err(io::Error::from_raw_os_error(e.as_usize())); |
| 34 | + } |
| 35 | + }; |
| 36 | + |
| 37 | + // Check if the key is printiable character |
| 38 | + if inp.scan_code != 0x00 { |
| 39 | + return Err(io::const_io_error!(io::ErrorKind::Interrupted, "Special Key Press")); |
| 40 | + } |
| 41 | + |
| 42 | + // SAFETY: Iterator will have only 1 character since we are reading only 1 Key |
| 43 | + // SAFETY: This character will always be UCS-2 and thus no surrogates. |
| 44 | + let ch: char = char::decode_utf16([inp.unicode_char]).next().unwrap().unwrap(); |
| 45 | + if ch.len_utf8() > buf.len() { |
| 46 | + return Ok(0); |
| 47 | + } |
| 48 | + |
| 49 | + ch.encode_utf8(buf); |
| 50 | + |
| 51 | + Ok(ch.len_utf8()) |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +impl Stdout { |
| 56 | + pub const fn new() -> Stdout { |
| 57 | + Stdout |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +impl io::Write for Stdout { |
| 62 | + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| 63 | + let st: NonNull<r_efi::efi::SystemTable> = uefi::env::system_table().cast(); |
| 64 | + let stdout = unsafe { (*st.as_ptr()).con_out }; |
| 65 | + |
| 66 | + write(stdout, buf) |
| 67 | + } |
| 68 | + |
| 69 | + fn flush(&mut self) -> io::Result<()> { |
| 70 | + Ok(()) |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +impl Stderr { |
| 75 | + pub const fn new() -> Stderr { |
| 76 | + Stderr |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +impl io::Write for Stderr { |
| 81 | + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| 82 | + let st: NonNull<r_efi::efi::SystemTable> = uefi::env::system_table().cast(); |
| 83 | + let stderr = unsafe { (*st.as_ptr()).std_err }; |
| 84 | + |
| 85 | + write(stderr, buf) |
| 86 | + } |
| 87 | + |
| 88 | + fn flush(&mut self) -> io::Result<()> { |
| 89 | + Ok(()) |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +// UCS-2 character should occupy 3 bytes at most in UTF-8 |
| 94 | +pub const STDIN_BUF_SIZE: usize = 3; |
| 95 | + |
| 96 | +pub fn is_ebadf(_err: &io::Error) -> bool { |
| 97 | + true |
| 98 | +} |
| 99 | + |
| 100 | +pub fn panic_output() -> Option<impl io::Write> { |
| 101 | + uefi::env::try_system_table().map(|_| Stderr::new()) |
| 102 | +} |
| 103 | + |
| 104 | +fn write( |
| 105 | + protocol: *mut r_efi::protocols::simple_text_output::Protocol, |
| 106 | + buf: &[u8], |
| 107 | +) -> io::Result<usize> { |
| 108 | + let mut utf16 = [0; MAX_BUFFER_SIZE / 2]; |
| 109 | + |
| 110 | + // Get valid UTF-8 buffer |
| 111 | + let utf8 = match crate::str::from_utf8(buf) { |
| 112 | + Ok(x) => x, |
| 113 | + Err(e) => unsafe { crate::str::from_utf8_unchecked(&buf[..e.valid_up_to()]) }, |
| 114 | + }; |
| 115 | + // Clip UTF-8 buffer to max UTF-16 buffer we support |
| 116 | + let utf8 = &utf8[..utf8.floor_char_boundary(utf16.len() - 1)]; |
| 117 | + |
| 118 | + for (i, ch) in utf8.encode_utf16().enumerate() { |
| 119 | + utf16[i] = ch; |
| 120 | + } |
| 121 | + |
| 122 | + unsafe { simple_text_output(protocol, &mut utf16) }?; |
| 123 | + |
| 124 | + Ok(utf8.len()) |
| 125 | +} |
| 126 | + |
| 127 | +unsafe fn simple_text_output( |
| 128 | + protocol: *mut r_efi::protocols::simple_text_output::Protocol, |
| 129 | + buf: &mut [u16], |
| 130 | +) -> io::Result<()> { |
| 131 | + let res = unsafe { ((*protocol).output_string)(protocol, buf.as_mut_ptr()) }; |
| 132 | + if res.is_error() { Err(io::Error::from_raw_os_error(res.as_usize())) } else { Ok(()) } |
| 133 | +} |
| 134 | + |
| 135 | +fn wait_stdin(stdin: *mut r_efi::protocols::simple_text_input::Protocol) -> io::Result<()> { |
| 136 | + let boot_services: NonNull<r_efi::efi::BootServices> = |
| 137 | + uefi::env::boot_services().unwrap().cast(); |
| 138 | + let wait_for_event = unsafe { (*boot_services.as_ptr()).wait_for_event }; |
| 139 | + let wait_for_key_event = unsafe { (*stdin).wait_for_key }; |
| 140 | + |
| 141 | + let r = { |
| 142 | + let mut x: usize = 0; |
| 143 | + (wait_for_event)(1, [wait_for_key_event].as_mut_ptr(), &mut x) |
| 144 | + }; |
| 145 | + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } |
| 146 | +} |
| 147 | + |
| 148 | +fn read_key_stroke( |
| 149 | + stdin: *mut r_efi::protocols::simple_text_input::Protocol, |
| 150 | +) -> Result<r_efi::protocols::simple_text_input::InputKey, r_efi::efi::Status> { |
| 151 | + let mut input_key: MaybeUninit<r_efi::protocols::simple_text_input::InputKey> = |
| 152 | + MaybeUninit::uninit(); |
| 153 | + |
| 154 | + let r = unsafe { ((*stdin).read_key_stroke)(stdin, input_key.as_mut_ptr()) }; |
| 155 | + |
| 156 | + if r.is_error() { |
| 157 | + Err(r) |
| 158 | + } else { |
| 159 | + let input_key = unsafe { input_key.assume_init() }; |
| 160 | + Ok(input_key) |
| 161 | + } |
| 162 | +} |
0 commit comments